Compare commits

..

37 commits
0.14.1 ... main

Author SHA1 Message Date
DreamMaoMao
a515ad9b91 feat: add overview jump mode
Some checks are pending
Sync website / sync-website (push) Waiting to run
Sync wiki / sync-wiki (push) Waiting to run
2026-06-16 23:08:01 +08:00
DreamMaoMao
24fb167ae6 bump version to 0.14.4 2026-06-16 14:37:58 +08:00
DreamMaoMao
1ae6adabc3 opt: ensure sel client exist in all monitor 2026-06-16 13:40:32 +08:00
DreamMaoMao
87f00ab5e9 fix: dwindle refuse arrange when restore from tty in non-selmon
dwindle relies on sel window cutting, but the sel window has been
cleared when the display is destroyed and was not set when the display
is created
2026-06-16 13:36:21 +08:00
DreamMaoMao
405e8dbc1a opt: format code 2026-06-16 08:20:55 +08:00
DreamMaoMao
71689f6ef4 opt: warp cursor to focusing client when exchange 2026-06-16 08:19:50 +08:00
DreamMaoMao
84a7d3d1e9 opt: better direction algorithm for client find 2026-06-16 08:08:43 +08:00
DreamMaoMao
ce1879d417 fix: scroller proportion option miss apply in windowrule 2026-06-16 08:07:54 +08:00
DreamMaoMao
d81ca73ea1 opt: optimzie dir find logic
Some checks are pending
Sync website / sync-website (push) Waiting to run
Sync wiki / sync-wiki (push) Waiting to run
2026-06-16 00:06:49 +08:00
DreamMaoMao
55d366daf2 bump version to 0.14.3 2026-06-15 20:44:31 +08:00
DreamMaoMao
ba014d5059 update docs 2026-06-15 16:56:03 +08:00
DreamMaoMao
b0fb99b95e feat: add scroller property to tagrule 2026-06-15 16:49:42 +08:00
DreamMaoMao
fa24c606a0 opt: optimize tag animaiton when tagout from overview 2026-06-15 13:43:56 +08:00
DreamMaoMao
8ca013e6c3 opt: avoid arrange when restore from overview 2026-06-15 13:33:46 +08:00
DreamMaoMao
8a3d065cc1 opt: add ov workspace before remove all tag workspace 2026-06-15 10:43:54 +08:00
DreamMaoMao
2a9c38df1f fix: cursor not auto hide in overview 2026-06-15 09:53:34 +08:00
DreamMaoMao
4daab9e4d5 opt: optimzie client layer judge in overveiw
Some checks are pending
Sync website / sync-website (push) Waiting to run
Sync wiki / sync-wiki (push) Waiting to run
2026-06-15 00:02:14 +08:00
DreamMaoMao
83adb33ad2 fix: overview cursor jump miss apply when no mousebind 2026-06-15 00:00:05 +08:00
DreamMaoMao
15fb37f1c6 update docs 2026-06-14 13:14:38 +08:00
DreamMaoMao
7e178369ff opt: optimize drop tile client when cross monitor 2026-06-14 07:53:57 +08:00
DreamMaoMao
792bfac475 fix: can't resize tile scroller window when only two tiled client 2026-06-11 23:14:50 +08:00
DreamMaoMao
03e68ba069 opt: optimize marco use in client tile resize 2026-06-11 12:39:17 +08:00
DreamMaoMao
33cda5afea opt:optimize edge focus judge 2026-06-11 12:37:48 +08:00
DreamMaoMao
94db68ef88 fix: floating window can't get pointer focus when cross monitor 2026-06-11 11:08:44 +08:00
DreamMaoMao
cd6e2883db
Merge pull request #1027 from xtheeq/docs-update
Some checks failed
Sync website / sync-website (push) Has been cancelled
Sync wiki / sync-wiki (push) Has been cancelled
docs: fix wayfreeze link page
2026-06-10 11:45:58 +08:00
DreamMaoMao
ef59224cdb fix: deck layout caculate error when multi master 2026-06-09 21:56:48 +08:00
DreamMaoMao
52732c928b fix: grid layout cant fullscreen 2026-06-09 21:50:16 +08:00
xtheeq
47f30454e6 docs: fix wayfreeze link page 2026-06-08 20:33:21 +05:30
DreamMaoMao
7faf9b6239 Merge pull request #1025 from osamamragab/main
feat: add hide cursor on keypress option (#871)
2026-06-08 21:44:13 +08:00
DreamMaoMao
36398a1af2 opt: optimize unmanaged client init 2026-06-08 19:29:00 +08:00
Osama Ragab
a429420b73 feat: add hide cursor on keypress option (#871) 2026-06-08 13:28:34 +08:00
DreamMaoMao
b8fa9a3043 Merge pull request #1025 from osamamragab/main
Some checks failed
Sync website / sync-website (push) Has been cancelled
Sync wiki / sync-wiki (push) Has been cancelled
feat: add hide cursor on keypress option (#871)
2026-06-08 13:28:34 +08:00
DreamMaoMao
009e2d2111 opt: optimzie xwayland position set 2026-06-08 13:05:04 +08:00
DreamMaoMao
27f4f64173 opt: not need send output enter when layer map
scene scene-graph API will auto do this
2026-06-08 11:40:51 +08:00
DreamMaoMao
ccb58a4f1a docs: fix some error im sample 2026-06-07 18:08:55 +08:00
DreamMaoMao
db8d22ae8e bump version to 0.14.2 2026-06-06 21:21:34 +08:00
DreamMaoMao
3ab2780b84 fix: excrescent gap in fullscreen 2026-06-06 18:16:08 +08:00
29 changed files with 1090 additions and 496 deletions

View file

@ -161,6 +161,7 @@ bindr=Super,Super_L,spawn,rofi -show run
| `reload_config` | - | Hot-reload configuration. |
| `quit` | - | Exit mangowm. |
| `toggleoverview` | - | Toggle overview mode. |
| `togglejump` | - | Toggle overview with jump mode. |
| `create_virtual_output` | - | Create a headless monitor (for VNC/Sunshine). |
| `destroy_all_virtual_output` | - | Destroy all virtual monitors. |
| `toggleoverlay` | - | Toggle overlay state for the focused window. |

View file

@ -21,6 +21,7 @@ description: Advanced settings for XWayland, focus behavior, and system integrat
| `sloppyfocus` | `1` | Focus follows the mouse cursor. |
| `warpcursor` | `1` | Warp the cursor to the center of the window when focus changes via keyboard. |
| `cursor_hide_timeout` | `0` | Hide the cursor after `N` seconds of inactivity (`0` to disable). |
| `cursor_hide_on_keypress` | `0` | Hide the cursor on keypress. |
| `drag_tile_to_tile` | `0` | Allow dragging a tiled window onto another to swap their positions. |
| `drag_tile_small` | `1` | Allow dragging a tiled window temporarily to small size.|
| `drag_corner` | `3` | Corner for drag-to-tile detection (0: none, 13: corners, 4: auto-detect). |

View file

@ -163,6 +163,8 @@ Some GPUs have compatibility issues with `syncobj_enable=1` — it may crash app
## Power Management
You can control monitor power using the `mmsg` IPC tool.
> Notice: This command does not remove the monitor, it only turns it off.
> if you want completely remove monitor, just use `wlr-randr`
```bash
# Turn off
@ -178,13 +180,13 @@ mmsg dispatch toggle_monitor,eDP-1
You can also use `wlr-randr` for monitor management:
```bash
# Turn off monitor
# remove a monitor
wlr-randr --output eDP-1 --off
# Turn on monitor
# add a monitor
wlr-randr --output eDP-1 --on
# Show all monitors
# Show all monitors spec
wlr-randr
```

View file

@ -274,6 +274,7 @@ If your distribution isn't listed above, or you want the latest unreleased chang
> - `hwdata`
> - `seatd`
> - `pcre2`
> - `pango`
> - `cjson`
> - `pixman`
> - `xorg-xwayland`

View file

@ -14,7 +14,7 @@ Instead, compose your own workflow from small Wayland utilities and bind them to
| [`slurp`](https://github.com/emersion/slurp) | Interactively select a region for `grim` |
| [`wl-copy`](https://github.com/bugaevc/wl-clipboard) | Copy screenshots directly to the clipboard |
| [`satty`](https://github.com/gabm/Satty) | Annotate screenshots before saving |
| [`wayfreeze`](https://github.com/nicbk/wayfreeze) | Freeze the screen before capture |
| [`wayfreeze`](https://github.com/Jappie3/wayfreeze) | Freeze the screen before capture |
Install the required with your package manager or from source.

View file

@ -52,6 +52,18 @@ You can also color-code windows based on their state:
> **Tip:** For scratchpad window sizing, see [Scratchpad](/docs/window-management/scratchpad) configuration.
### Overview Jump Mode
| Setting | Default | Description |
| :--- | :--- | :--- |
| `jump_hit_fg_color` | `0xc4939dff` | label text color. |
| `jump_hit_bg_color` | `0x201b14ff` | label background color.
| `jump_hit_border_color` | `0x8BAA9Bff` | label border color.
| `jump_hit_border_width` | `4` | label border width.
| `jump_hit_corner_radius` | `5` | label corner radius.
| `jump_hit_padding_x` | `10` | label horizontal padding.
| `jump_hit_padding_y` | `10` | label vertical padding.
| `jump_hit_font_desc` | `monospace Bold 24` | label font set.|
## Cursor Theme
Set the size and theme of your mouse cursor.

View file

@ -115,7 +115,7 @@ windowrule=width:1000,height:900,appid:yesplaymusic,title:Demons
# Global keybindings for OBS Studio
windowrule=globalkeybinding:ctrl+alt-o,appid:com.obsproject.Studio
windowrule=globalkeybinding:ctrl+alt+n,appid:com.obsproject.Studio
windowrule=globalkeybinding:ctrl+alt-n,appid:com.obsproject.Studio
windowrule=isopensilent:1,appid:com.obsproject.Studio
# Force tearing for games
@ -183,6 +183,9 @@ tagrule=id:Values,monitor_make:xxx,monitor_model:xxx,Parameter:Values
| `no_hide` | integer | `0` / `1` | Not hide even if the tag is empty |
| `nmaster` | integer | 0, 99 | Number of master windows |
| `mfact` | float | 0.10.9 | Master area factor |
| `scroller_default_proportion` | float | 0.1-1.0 | Set scroller default proportion. |
| `scroller_default_proportion_single` | float | 0.1-1.0 | Set scroller auto adjust proportion when it is single window(only apply when set `scroller_ignore_proportion_single` to `0`) |
| `scroller_ignore_proportion_single` | integer | `0` / `1` | Ignore scroller single proportion setting. |
### Examples
@ -204,6 +207,10 @@ tagrule=id:4,monitor_name:eDP-1,no_hide:1,layout_name:scroller
# Advanced tag configuration with master layout settings
tagrule=id:5,layout_name:tile,nmaster:2,mfact:0.6
tagrule=id:6,monitor_name:HDMI-A-1,layout_name:monocle,no_render_border:1
# set scroller proportion for specific tag
tagrule=id:1,layout_name:scroller,scroller_default_proportion_single:0.5,scroller_ignore_proportion_single:0,scroller_default_proportion:0.9,monitor_name:HDMI-A-1
```
> **Tip:** For Waybar configuration with persistent tags, see [Status Bar](/docs/visuals/status-bar) documentation.

View file

@ -54,6 +54,7 @@
hwdata
seatd
pcre2
pango
cjson
libxcb
pixman

View file

@ -1,5 +1,5 @@
project('mango', ['c'],
version : '0.14.1',
version : '0.14.4',
)
subdir('protocols')
@ -37,6 +37,7 @@ pcre2_dep = dependency('libpcre2-8')
libscenefx_dep = dependency('scenefx-0.4',version: '>=0.4.1')
pixman_dep = dependency('pixman-1')
cjson_dep = dependency('libcjson')
pangocairo_dep = dependency('pangocairo')
# version info
git = find_program('git', required : false)
@ -94,6 +95,7 @@ endif
executable('mango',
'src/mango.c',
'src/common/util.c',
'src/draw/text-node.c',
'src/ext-protocol/wlr_ext_workspace_v1.c',
wayland_sources,
dependencies : [
@ -109,6 +111,7 @@ executable('mango',
pcre2_dep,
pixman_dep,
cjson_dep,
pangocairo_dep,
],
install : true,
c_args : c_args,

View file

@ -5,6 +5,7 @@
libxcb,
libxkbcommon,
pcre2,
pango,
cjson,
pixman,
pkg-config,
@ -49,6 +50,7 @@ stdenv.mkDerivation {
libxcb
libxkbcommon
pcre2
pango
cjson
pixman
wayland

View file

@ -48,10 +48,13 @@ static void finish_exchange_arrange_and_focus(Client *c1, Client *c2,
}
wl_list_remove(&c2->flink);
wl_list_insert(&c1->flink, &c2->flink);
if (config.warpcursor)
warp_cursor(c1);
}
void client_tile_resize(Client *c, struct wlr_box geo, int32_t interact) {
if (!ISSCROLLTILED(c))
if (!ISFAKETILED(c))
return;
if (!c->isfullscreen && !c->ismaximizescreen) {

View file

@ -495,6 +495,7 @@ void apply_border(Client *c) {
if (c->isfullscreen) {
if (c->border->node.enabled) {
wlr_scene_node_set_position(&c->scene_surface->node, 0, 0);
wlr_scene_node_set_enabled(&c->border->node, false);
}
return;
@ -698,17 +699,6 @@ void client_set_drop_area(Client *c) {
bool dwindle_familiar =
cur_layout->id == DWINDLE && config.dwindle_drop_simple_split;
uint32_t nmaster = c->mon->pertag->nmasters[c->mon->pertag->curtag];
bool should_swap =
(cur_layout->id == DECK || cur_layout->id == VERTICAL_DECK ||
cur_layout->id == MONOCLE || cur_layout->id == GRID ||
cur_layout->id == FAIR || cur_layout->id == VERTICAL_FAIR ||
cur_layout->id == VERTICAL_GRID) ||
((cur_layout->id == TILE || cur_layout->id == VERTICAL_TILE ||
cur_layout->id == CENTER_TILE || cur_layout->id == RIGHT_TILE) &&
nmaster == 1 && c->ismaster);
if (dwindle_familiar) {
bool split_h = c->geom.width >= c->geom.height;
float ratio = config.dwindle_split_ratio;
@ -742,29 +732,11 @@ void client_set_drop_area(Client *c) {
client_height - (int32_t)(client_height * ratio);
}
}
} else if (should_swap) {
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height;
drop_direction = UNDIR;
} else if (cur_layout->id == TILE || cur_layout->id == DECK ||
cur_layout->id == CENTER_TILE || cur_layout->id == RIGHT_TILE) {
if (rel_y < client_height * 0.5) {
drop_direction = UP;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height / 2;
} else {
drop_direction = DOWN;
drop_box.x = bw;
drop_box.y = bw + client_height / 2;
drop_box.width = client_width;
drop_box.height = client_height / 2;
}
} else if (cur_layout->id == VERTICAL_TILE ||
cur_layout->id == VERTICAL_DECK) {
if (c->ismaster) {
if (c->mon->visible_tiling_clients == 1) {
if (rel_x < client_width * 0.5) {
drop_direction = LEFT;
drop_box.x = bw;
@ -778,6 +750,69 @@ void client_set_drop_area(Client *c) {
drop_box.width = client_width / 2;
drop_box.height = client_height;
}
} else {
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height;
drop_direction = UNDIR;
}
} else {
if (rel_y < client_height * 0.5) {
drop_direction = UP;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height / 2;
} else {
drop_direction = DOWN;
drop_box.x = bw;
drop_box.y = bw + client_height / 2;
drop_box.width = client_width;
drop_box.height = client_height / 2;
}
}
} else if (cur_layout->id == VERTICAL_TILE ||
cur_layout->id == VERTICAL_DECK) {
if (c->ismaster) {
if (c->mon->visible_tiling_clients == 1) {
if (rel_y < client_height * 0.5) {
drop_direction = UP;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height / 2;
} else {
drop_direction = DOWN;
drop_box.x = bw;
drop_box.y = bw + client_height / 2;
drop_box.width = client_width;
drop_box.height = client_height / 2;
}
} else {
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height;
drop_direction = UNDIR;
}
} else {
if (rel_x < client_width * 0.5) {
drop_direction = LEFT;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
} else {
drop_direction = RIGHT;
drop_box.x = bw + client_width / 2;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
}
}
} else {
double dist_left = rel_x;
double dist_right = client_width - rel_x;

View file

@ -117,6 +117,9 @@ void set_arrange_hidden(Monitor *m, Client *c, bool want_animation) {
c->animation.tagining = false;
set_tagout_animation(m, c);
} else {
c->animation.running = false;
wlr_scene_node_set_enabled(&c->scene->node, false);
c->animainit_geom = c->current = c->pending = c->animation.current =
c->geom;
}
}

View file

@ -167,6 +167,9 @@ typedef struct {
char *monitor_serial;
float mfact;
int32_t nmaster;
float scroller_default_proportion;
float scroller_default_proportion_single;
int32_t scroller_ignore_proportion_single;
int32_t no_render_border;
int32_t open_as_floating;
int32_t no_hide;
@ -258,9 +261,11 @@ typedef struct {
int32_t enable_hotarea;
int32_t ov_tab_mode;
int32_t ov_no_resize;
int32_t overviewgappi;
int32_t overviewgappo;
uint32_t cursor_hide_timeout;
uint32_t cursor_hide_on_keypress;
uint32_t axis_bind_apply_timeout;
uint32_t focus_on_activate;
@ -403,6 +408,7 @@ typedef struct {
struct xkb_context *ctx;
struct xkb_keymap *keymap;
JumphitData jumhitdata;
} Config;
typedef int32_t (*FuncType)(const Arg *);
@ -1026,6 +1032,9 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
} else if (strcmp(func_name, "toggleoverview") == 0) {
func = toggleoverview;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "togglejump") == 0) {
func = togglejump;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "set_proportion") == 0) {
func = set_proportion;
(*arg).f = atof(arg_value);
@ -1714,6 +1723,8 @@ bool parse_option(Config *config, char *key, char *value) {
config->overviewgappo = atoi(value);
} else if (strcmp(key, "cursor_hide_timeout") == 0) {
config->cursor_hide_timeout = atoi(value);
} else if (strcmp(key, "cursor_hide_on_keypress") == 0) {
config->cursor_hide_on_keypress = atoi(value);
} else if (strcmp(key, "axis_bind_apply_timeout") == 0) {
config->axis_bind_apply_timeout = atoi(value);
} else if (strcmp(key, "focus_on_activate") == 0) {
@ -1752,6 +1763,50 @@ bool parse_option(Config *config, char *key, char *value) {
config->cursor_size = atoi(value);
} else if (strcmp(key, "cursor_theme") == 0) {
config->cursor_theme = strdup(value);
} else if (strcmp(key, "jump_hit_fg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid jump_hit_fg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumhitdata.fg_color, color);
}
} else if (strcmp(key, "jump_hit_font_desc") == 0) {
config->jumhitdata.font_desc = strdup(value);
} else if (strcmp(key, "jump_hit_bg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid jump_hit_bg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumhitdata.bg_color, color);
}
} else if (strcmp(key, "jump_hit_border_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(
stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid jump_hit_border_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumhitdata.border_color, color);
}
} else if (strcmp(key, "jump_hit_border_width") == 0) {
config->jumhitdata.border_width = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_hit_corner_radius") == 0) {
config->jumhitdata.corner_radius = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_hit_padding_x") == 0) {
config->jumhitdata.padding_x = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_hit_padding_y") == 0) {
config->jumhitdata.padding_y = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "disable_while_typing") == 0) {
config->disable_while_typing = atoi(value);
} else if (strcmp(key, "left_handed") == 0) {
@ -2038,6 +2093,9 @@ bool parse_option(Config *config, char *key, char *value) {
rule->no_render_border = 0;
rule->open_as_floating = 0;
rule->no_hide = 0;
rule->scroller_default_proportion = 0.0f;
rule->scroller_default_proportion_single = 0.0f;
rule->scroller_ignore_proportion_single = -1;
bool parse_error = false;
char *token = strtok(value, ",");
@ -2073,6 +2131,17 @@ bool parse_option(Config *config, char *key, char *value) {
rule->nmaster = CLAMP_INT(atoi(val), 1, 99);
} else if (strcmp(key, "mfact") == 0) {
rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f);
} else if (strcmp(key, "scroller_default_proportion") == 0) {
rule->scroller_default_proportion =
CLAMP_FLOAT(atof(val), 0.0f, 1.0f);
} else if (strcmp(key, "scroller_default_proportion_single") ==
0) {
rule->scroller_default_proportion_single =
CLAMP_FLOAT(atof(val), 0.0f, 1.0f);
} else if (strcmp(key, "scroller_ignore_proportion_single") ==
0) {
rule->scroller_ignore_proportion_single =
CLAMP_INT(atoi(val), 0, 1);
} else {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown "
@ -3227,6 +3296,11 @@ void free_config(void) {
config.cursor_theme = NULL;
}
if (config.jumhitdata.font_desc) {
free((void *)config.jumhitdata.font_desc);
config.jumhitdata.font_desc = NULL;
}
if (config.tablet_map_to_mon) {
free(config.tablet_map_to_mon);
config.tablet_map_to_mon = NULL;
@ -3346,6 +3420,8 @@ void override_config(void) {
CLAMP_INT(config.no_radius_when_single, 0, 1);
config.cursor_hide_timeout =
CLAMP_INT(config.cursor_hide_timeout, 0, 36000);
config.cursor_hide_on_keypress =
CLAMP_INT(config.cursor_hide_on_keypress, 0, 1);
config.single_scratchpad = CLAMP_INT(config.single_scratchpad, 0, 1);
config.repeat_rate = CLAMP_INT(config.repeat_rate, 1, 1000);
config.repeat_delay = CLAMP_INT(config.repeat_delay, 1, 20000);
@ -3415,6 +3491,15 @@ void override_config(void) {
config.focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f);
config.unfocused_opacity =
CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f);
config.jumhitdata.border_width =
CLAMP_INT(config.jumhitdata.border_width, 0, 100);
config.jumhitdata.corner_radius =
CLAMP_INT(config.jumhitdata.corner_radius, 0, 100);
config.jumhitdata.padding_x =
CLAMP_INT(config.jumhitdata.padding_x, 0, 100);
config.jumhitdata.padding_y =
CLAMP_INT(config.jumhitdata.padding_y, 0, 100);
}
void set_value_default() {
@ -3453,7 +3538,6 @@ void set_value_default() {
config.log_level = WLR_ERROR;
config.numlockon = 0;
config.capslock = 0;
config.ov_tab_mode = 1;
config.ov_no_resize = 1;
config.hotarea_size = 10;
@ -3507,6 +3591,7 @@ void set_value_default() {
config.overviewgappi = 5;
config.overviewgappo = 30;
config.cursor_hide_timeout = 0;
config.cursor_hide_on_keypress = 0;
config.warpcursor = 1;
config.drag_corner = 3;
@ -3590,6 +3675,23 @@ void set_value_default() {
config.animation_curve_opafadeout[2] = 0.5;
config.animation_curve_opafadeout[3] = 0.5;
config.jumhitdata.fg_color[0] = 0xc4 / 255.0f;
config.jumhitdata.fg_color[1] = 0x93 / 255.0f;
config.jumhitdata.fg_color[2] = 0x9d / 255.0f;
config.jumhitdata.fg_color[3] = 1.0f;
config.jumhitdata.bg_color[0] = 0x32 / 255.0f;
config.jumhitdata.bg_color[1] = 0x32 / 255.0f;
config.jumhitdata.bg_color[2] = 0x32 / 255.0f;
config.jumhitdata.bg_color[3] = 1.0f;
config.jumhitdata.border_color[0] = 0x8b / 255.0f;
config.jumhitdata.border_color[1] = 0xaa / 255.0f;
config.jumhitdata.border_color[2] = 0x9b / 255.0f;
config.jumhitdata.border_color[3] = 1.0f;
config.jumhitdata.border_width = 4;
config.jumhitdata.corner_radius = 5;
config.jumhitdata.padding_x = 10;
config.jumhitdata.padding_y = 10;
config.rootcolor[0] = 0x32 / 255.0f;
config.rootcolor[1] = 0x32 / 255.0f;
config.rootcolor[2] = 0x32 / 255.0f;
@ -3702,6 +3804,7 @@ bool parse_config(void) {
config.tag_rules = NULL;
config.tag_rules_count = 0;
config.cursor_theme = NULL;
config.jumhitdata.font_desc = NULL;
config.tablet_map_to_mon = NULL;
strcpy(config.keymode, "default");
@ -3928,6 +4031,12 @@ void parse_tagrule(Monitor *m) {
for (i = 0; i <= LENGTH(tags); i++) {
m->pertag->nmasters[i] = config.default_nmaster;
m->pertag->mfacts[i] = config.default_mfact;
m->pertag->scroller_default_proportion[i] =
config.scroller_default_proportion;
m->pertag->scroller_default_proportion_single[i] =
config.scroller_default_proportion_single;
m->pertag->scroller_ignore_proportion_single[i] =
config.scroller_ignore_proportion_single;
}
for (i = 0; i < config.tag_rules_count; i++) {
@ -3982,6 +4091,15 @@ void parse_tagrule(Monitor *m) {
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;
if (tr.scroller_default_proportion > 0.0f)
m->pertag->scroller_default_proportion[tr.id] =
tr.scroller_default_proportion;
if (tr.scroller_default_proportion_single > 0.0f)
m->pertag->scroller_default_proportion_single[tr.id] =
tr.scroller_default_proportion_single;
if (tr.scroller_ignore_proportion_single >= 0)
m->pertag->scroller_ignore_proportion_single[tr.id] =
tr.scroller_ignore_proportion_single;
}
}

View file

@ -3,6 +3,7 @@ int32_t restore_minimized(const Arg *arg);
int32_t toggle_scratchpad(const Arg *arg);
int32_t focusdir(const Arg *arg);
int32_t toggleoverview(const Arg *arg);
int32_t togglejump(const Arg *arg);
int32_t set_proportion(const Arg *arg);
int32_t switch_proportion_preset(const Arg *arg);
int32_t zoom(const Arg *arg);

View file

@ -130,8 +130,13 @@ int32_t exchange_stack_client(const Arg *arg) {
}
int32_t focusdir(const Arg *arg) {
if (!selmon)
return 0;
Client *c = NULL;
c = direction_select(arg);
if (!selmon->isoverview)
c = get_focused_stack_client(c, arg->tc);
if (c) {
focusclient(c, 1);
@ -1355,9 +1360,9 @@ int32_t togglefullscreen(const Arg *arg) {
sel->isnamedscratchpad = 0;
if (sel->isfullscreen)
setfullscreen(sel, 0);
setfullscreen(sel, 0, true);
else
setfullscreen(sel, 1);
setfullscreen(sel, 1, true);
return 0;
}
@ -1401,9 +1406,9 @@ int32_t togglemaximizescreen(const Arg *arg) {
sel->isnamedscratchpad = 0;
if (sel->ismaximizescreen)
setmaximizescreen(sel, 0);
setmaximizescreen(sel, 0, true);
else
setmaximizescreen(sel, 1);
setmaximizescreen(sel, 1, true);
setborder_color(sel);
return 0;
@ -1732,6 +1737,10 @@ int32_t toggleoverview(const Arg *arg) {
uint32_t target;
uint32_t visible_client_number = 0;
if (!selmon->isoverview && selmon->is_jump_mode) {
finish_jump_mode(selmon);
}
if (selmon->isoverview) {
wl_list_for_each(c, &clients, link) if (c && c->mon == selmon &&
!client_is_unmanaged(c) &&
@ -1760,7 +1769,12 @@ int32_t toggleoverview(const Arg *arg) {
if (selmon->isoverview) {
wlr_seat_pointer_clear_focus(seat);
if (cursor_hidden) {
handlecursoractivity();
} else {
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
}
wl_list_for_each(c, &clients, link) {
if (c && c->mon == selmon && !client_is_unmanaged(c) &&
@ -1771,6 +1785,7 @@ int32_t toggleoverview(const Arg *arg) {
}
}
} else {
selmon->tagset[selmon->seltags] = target;
wl_list_for_each(c, &clients, link) {
if (c && c->mon == selmon && !c->iskilling &&
@ -1784,6 +1799,24 @@ int32_t toggleoverview(const Arg *arg) {
view(&(Arg){.ui = target}, false);
fix_mon_tagset_from_overview(selmon);
refresh_monitors_workspaces_status(selmon);
return 0;
}
int32_t togglejump(const Arg *arg) {
if (!selmon)
return 0;
if (!selmon->isoverview) {
begin_jump_mode(selmon);
toggleoverview(arg);
return 0;
}
if (selmon->isoverview) {
toggleoverview(arg);
}
return 0;
}
@ -1913,7 +1946,7 @@ int32_t scroller_stack(const Arg *arg) {
if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon))
return 0;
Client *target_client = find_client_by_direction(c, arg, false, true);
Client *target_client = find_client_by_direction(c, arg, false);
return scroller_apply_stack(c, target_client, arg->i);
}

308
src/draw/text-node.c Normal file
View file

@ -0,0 +1,308 @@
#include "text-node.h"
#include <cairo.h>
#include <drm_fourcc.h>
#include <glib.h>
#include <pango/pangocairo.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/interfaces/wlr_buffer.h>
// 自定义 wlr_buffer用于将 Cairo Surface 包装并注入 wlr_scene
struct mango_text_buffer {
struct wlr_buffer base;
cairo_surface_t *surface;
};
// 全局字体描述缓存
static GHashTable *font_desc_cache = NULL;
static PangoFontDescription *get_cached_font_desc(const char *font_desc) {
if (!font_desc_cache) {
font_desc_cache =
g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify)pango_font_description_free);
}
PangoFontDescription *desc =
g_hash_table_lookup(font_desc_cache, font_desc);
if (!desc) {
desc = pango_font_description_from_string(font_desc);
g_hash_table_insert(font_desc_cache, g_strdup(font_desc), desc);
}
return desc;
}
void mango_text_global_finish(void) {
if (font_desc_cache) {
g_hash_table_destroy(font_desc_cache);
font_desc_cache = NULL;
}
}
// wlr_buffer 实现
static void text_buffer_destroy(struct wlr_buffer *wlr_buffer) {
struct mango_text_buffer *buf = wl_container_of(wlr_buffer, buf, base);
cairo_surface_destroy(buf->surface);
free(buf);
}
static bool text_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
uint32_t flags, void **data,
uint32_t *format,
size_t *stride) {
(void)flags;
struct mango_text_buffer *buf = wl_container_of(wlr_buffer, buf, base);
*data = cairo_image_surface_get_data(buf->surface);
*format = DRM_FORMAT_ARGB8888;
*stride = cairo_image_surface_get_stride(buf->surface);
return true;
}
static void text_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {}
static const struct wlr_buffer_impl text_buffer_impl = {
.destroy = text_buffer_destroy,
.begin_data_ptr_access = text_buffer_begin_data_ptr_access,
.end_data_ptr_access = text_buffer_end_data_ptr_access,
};
struct mango_text_node *mango_text_node_create(struct wlr_scene_tree *parent,
JumphitData data) {
struct mango_text_node *node = calloc(1, sizeof(*node));
if (!node)
return NULL;
node->scene_buffer = wlr_scene_buffer_create(parent, NULL);
if (!node->scene_buffer) {
free(node);
return NULL;
}
node->fg_color[0] = data.fg_color[0];
node->fg_color[1] = data.fg_color[1];
node->fg_color[2] = data.fg_color[2];
node->fg_color[3] = data.fg_color[3];
node->bg_color[0] = data.bg_color[0];
node->bg_color[1] = data.bg_color[1];
node->bg_color[2] = data.bg_color[2];
node->bg_color[3] = data.bg_color[3];
node->border_color[0] = data.border_color[0];
node->border_color[1] = data.border_color[1];
node->border_color[2] = data.border_color[2];
node->border_color[3] = data.border_color[3];
node->border_width = data.border_width;
node->corner_radius = data.corner_radius;
node->padding_x = data.padding_x;
node->padding_y = data.padding_y;
node->font_desc = data.font_desc ? data.font_desc : "monospace Bold 24";
return node;
}
void mango_text_node_destroy(struct mango_text_node *node) {
if (!node)
return;
wlr_scene_node_destroy(&node->scene_buffer->node);
free(node);
}
void mango_text_node_set_background(struct mango_text_node *node, float r,
float g, float b, float a) {
if (!node)
return;
node->bg_color[0] = r;
node->bg_color[1] = g;
node->bg_color[2] = b;
node->bg_color[3] = a;
}
void mango_text_node_set_border(struct mango_text_node *node, float r, float g,
float b, float a, float width, float radius) {
if (!node)
return;
node->border_color[0] = r;
node->border_color[1] = g;
node->border_color[2] = b;
node->border_color[3] = a;
node->border_width = width > 0.0f ? width : 0.0f;
node->corner_radius = radius >= 0.0f ? radius : 0.0f;
}
void mango_text_node_set_padding(struct mango_text_node *node, float pad_x,
float pad_y) {
if (!node)
return;
node->padding_x = pad_x >= 0.0f ? pad_x : 0.0f;
node->padding_y = pad_y >= 0.0f ? pad_y : 0.0f;
}
static void draw_rounded_rect(cairo_t *cr, double x, double y, double w,
double h, double r) {
// 使用 Cairo 的标准圆角矩形路径
double degrees = G_PI / 180.0;
cairo_new_sub_path(cr);
cairo_arc(cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees);
cairo_arc(cr, x + w - r, y + h - r, r, 0 * degrees, 90 * degrees);
cairo_arc(cr, x + r, y + h - r, r, 90 * degrees, 180 * degrees);
cairo_arc(cr, x + r, y + r, r, 180 * degrees, 270 * degrees);
cairo_close_path(cr);
}
void mango_text_node_update(struct mango_text_node *node, const char *text,
float scale) {
if (!node || !text)
return;
if (scale <= 0.0f)
scale = 1.0f;
const char *font_desc = node->font_desc;
PangoFontDescription *desc = get_cached_font_desc(font_desc);
// 测量文字像素尺寸(无缩放的实际像素)
cairo_surface_t *dummy_surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
cairo_t *dummy_cr = cairo_create(dummy_surface);
PangoContext *dummy_ctx = pango_cairo_create_context(dummy_cr);
pango_cairo_context_set_resolution(dummy_ctx, 96.0 * scale);
PangoLayout *dummy_layout = pango_layout_new(dummy_ctx);
pango_layout_set_font_description(dummy_layout, desc);
pango_layout_set_text(dummy_layout, text, -1);
int text_pixel_w, text_pixel_h;
pango_layout_get_pixel_size(dummy_layout, &text_pixel_w, &text_pixel_h);
g_object_unref(dummy_layout);
g_object_unref(dummy_ctx);
cairo_destroy(dummy_cr);
cairo_surface_destroy(dummy_surface);
if (text_pixel_w <= 0 || text_pixel_h <= 0) {
wlr_scene_buffer_set_buffer(node->scene_buffer, NULL);
node->logical_width = 0;
node->logical_height = 0;
return;
}
float logical_text_w = text_pixel_w / scale;
float logical_text_h = text_pixel_h / scale;
float pad_x = node->padding_x;
float pad_y = node->padding_y;
float box_logical_w = logical_text_w + 2.0f * pad_x;
float box_logical_h = logical_text_h + 2.0f * pad_y;
float border = node->border_width;
bool draw_border = (border > 0.0f) && (node->border_color[3] > 0.0f);
bool draw_bg = (node->bg_color[3] > 0.0f);
int surface_pixel_w = (int)((box_logical_w + 2.0f * border) * scale + 0.5f);
int surface_pixel_h = (int)((box_logical_h + 2.0f * border) * scale + 0.5f);
if (surface_pixel_w < 1)
surface_pixel_w = 1;
if (surface_pixel_h < 1)
surface_pixel_h = 1;
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, surface_pixel_w, surface_pixel_h);
cairo_t *cr = cairo_create(surface);
// 清空为全透明
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
double bg_x = border * scale;
double bg_y = border * scale;
double bg_w = box_logical_w * scale;
double bg_h = box_logical_h * scale;
double radius = node->corner_radius * scale;
if (radius < 0) {
radius = (bg_w < bg_h ? bg_w : bg_h) / 2.0;
}
if (radius > bg_w / 2.0)
radius = bg_w / 2.0;
if (radius > bg_h / 2.0)
radius = bg_h / 2.0;
if (draw_bg) {
cairo_set_source_rgba(cr, node->bg_color[0], node->bg_color[1],
node->bg_color[2], node->bg_color[3]);
if (radius > 0.0) {
draw_rounded_rect(cr, bg_x, bg_y, bg_w, bg_h, radius);
cairo_fill(cr);
} else {
cairo_rectangle(cr, bg_x, bg_y, bg_w, bg_h);
cairo_fill(cr);
}
}
cairo_save(cr);
cairo_translate(cr, (border + pad_x) * scale, (border + pad_y) * scale);
PangoContext *ctx = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(ctx, 96.0 * scale);
PangoLayout *layout = pango_layout_new(ctx);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, text, -1);
cairo_set_source_rgba(cr, node->fg_color[0], node->fg_color[1],
node->fg_color[2], node->fg_color[3]);
pango_cairo_show_layout(cr, layout);
g_object_unref(layout);
g_object_unref(ctx);
cairo_restore(cr);
if (draw_border) {
cairo_set_source_rgba(cr, node->border_color[0], node->border_color[1],
node->border_color[2], node->border_color[3]);
cairo_set_line_width(cr, border * scale);
double half_lw = border * scale * 0.5;
double bx = bg_x - half_lw;
double by = bg_y - half_lw;
double bw = bg_w + border * scale;
double bh = bg_h + border * scale;
if (radius > 0.0) {
double outer_radius = radius + half_lw;
if (outer_radius < 0.0)
outer_radius = 0.0;
draw_rounded_rect(cr, bx, by, bw, bh, outer_radius);
cairo_stroke(cr);
} else {
cairo_rectangle(cr, bx, by, bw, bh);
cairo_stroke(cr);
}
}
cairo_surface_flush(surface);
// 包装成 wlr_buffer
struct mango_text_buffer *buf = calloc(1, sizeof(*buf));
if (!buf) {
cairo_surface_destroy(surface);
cairo_destroy(cr);
return;
}
wlr_buffer_init(&buf->base, &text_buffer_impl, surface_pixel_w,
surface_pixel_h);
buf->surface = surface;
wlr_scene_buffer_set_buffer(node->scene_buffer, &buf->base);
wlr_buffer_drop(&buf->base);
// 最终逻辑大小 = 背景框逻辑尺寸 + 边框逻辑尺寸
node->logical_width = (int)(box_logical_w + 2.0f * border);
node->logical_height = (int)(box_logical_h + 2.0f * border);
wlr_scene_buffer_set_dest_size(node->scene_buffer, node->logical_width,
node->logical_height);
cairo_destroy(cr);
}

52
src/draw/text-node.h Normal file
View file

@ -0,0 +1,52 @@
#ifndef MANGO_TEXT_NODE_H
#define MANGO_TEXT_NODE_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
struct mango_text_node {
struct wlr_scene_buffer *scene_buffer;
int logical_width;
int logical_height;
const char *font_desc;
// 外观属性
float fg_color[4]; // 文本颜色 RGBA默认白色
float bg_color[4]; // 背景色 RGBA默认透明
float border_color[4]; // 边框色 RGBA默认透明
int32_t border_width; // 边框宽度(逻辑像素),<=0 则不绘制
int32_t corner_radius; // 圆角半径(逻辑像素),<0 时自动取
// min(width,height)/2 形成胶囊
int32_t padding_x; // 文本左右内边距(逻辑像素)
int32_t padding_y; // 文本上下内边距(逻辑像素)
};
typedef struct {
float fg_color[4];
float bg_color[4];
float border_color[4];
int32_t border_width;
int32_t corner_radius;
int32_t padding_x;
int32_t padding_y;
const char *font_desc;
} JumphitData;
struct mango_text_node *mango_text_node_create(struct wlr_scene_tree *parent,
JumphitData data);
void mango_text_node_destroy(struct mango_text_node *node);
void mango_text_node_update(struct mango_text_node *node, const char *text,
float scale);
// 外观设置接口
void mango_text_node_set_background(struct mango_text_node *node, float r,
float g, float b, float a);
void mango_text_node_set_border(struct mango_text_node *node, float r, float g,
float b, float a, float width, float radius);
void mango_text_node_set_padding(struct mango_text_node *node, float pad_x,
float pad_y);
void mango_text_node_destroy(struct mango_text_node *node);
void mango_text_global_finish(void);
#endif

View file

@ -188,10 +188,10 @@ void refresh_monitors_workspaces_status(Monitor *m) {
int32_t i;
if (m->isoverview) {
add_workspace_by_tag(0, m);
for (i = 1; i <= LENGTH(tags); i++) {
remove_workspace_by_tag(i, m);
}
add_workspace_by_tag(0, m);
} else {
remove_workspace_by_tag(0, m);
for (i = 1; i <= LENGTH(tags); i++) {

View file

@ -16,12 +16,12 @@ void handle_foreign_maximize_request(struct wl_listener *listener, void *data) {
return;
if (c->ismaximizescreen && !event->maximized) {
setmaximizescreen(c, 0);
setmaximizescreen(c, 0, true);
return;
}
if (!c->ismaximizescreen && event->maximized) {
setmaximizescreen(c, 1);
setmaximizescreen(c, 1, true);
return;
}
}
@ -59,12 +59,12 @@ void handle_foreign_fullscreen_request(struct wl_listener *listener,
return;
if (c->isfullscreen && !event->fullscreen) {
setfullscreen(c, 0);
setfullscreen(c, 0, true);
return;
}
if (!c->isfullscreen && event->fullscreen) {
setfullscreen(c, 1);
setfullscreen(c, 1, true);
return;
}
}

View file

@ -91,9 +91,9 @@ setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom,
if (!m)
return geom;
uint32_t cbw = check_hit_no_border(c) ? c->bw : 0;
uint32_t cbw = c && check_hit_no_border(c) ? c->bw : 0;
if (!c->no_force_center && m) {
if ((!c || !c->no_force_center) && m) {
tempbox.x = m->w.x + (m->w.width - geom.width) / 2;
tempbox.y = m->w.y + (m->w.height - geom.height) / 2;
} else {
@ -163,291 +163,130 @@ Client *center_tiled_select(Monitor *m) {
}
return target_c;
}
Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating,
bool ignore_align) {
Client *find_client_by_direction(Client *tc, const Arg *arg,
bool findfloating) {
Client *c = NULL;
Client **tempClients = NULL; // 初始化为 NULL
int32_t last = -1;
// 第一次遍历,计算客户端数量
wl_list_for_each(c, &clients, link) {
if (c && (findfloating || !c->isfloating) && !c->isunglobal &&
(config.focus_cross_monitor || c->mon == tc->mon) &&
(c->tags & c->mon->tagset[c->mon->seltags])) {
last++;
}
}
if (last < 0) {
return NULL; // 没有符合条件的客户端
}
// 动态分配内存
tempClients = malloc((last + 1) * sizeof(Client *));
if (!tempClients) {
// 处理内存分配失败的情况
return NULL;
}
// 第二次遍历,填充 tempClients
last = -1;
wl_list_for_each(c, &clients, link) {
if (c && (findfloating || !c->isfloating) && !c->isunglobal &&
(config.focus_cross_monitor || c->mon == tc->mon) &&
(c->tags & c->mon->tagset[c->mon->seltags])) {
last++;
tempClients[last] = c;
}
}
int32_t sel_x = tc->geom.x;
int32_t sel_y = tc->geom.y;
int64_t distance = LLONG_MAX;
int64_t same_monitor_distance = LLONG_MAX;
Client *tempFocusClients = NULL;
Client *tempSameMonitorFocusClients = NULL;
int64_t distance = LLONG_MAX;
int64_t same_monitor_distance = LLONG_MAX;
int32_t tc_l = tc->geom.x;
int32_t tc_r = tc->geom.x + tc->geom.width;
int32_t tc_t = tc->geom.y;
int32_t tc_b = tc->geom.y + tc->geom.height;
int32_t tc_cx = tc_l + tc->geom.width / 2;
int32_t tc_cy = tc_t + tc->geom.height / 2;
for (int32_t step = 0; step < 2; step++) {
if (step == 1 && tempFocusClients)
break;
wl_list_for_each(c, &clients, link) {
if (!c || c == tc)
continue;
if (!findfloating && c->isfloating)
continue;
if (c->isunglobal)
continue;
if (!config.focus_cross_monitor && c->mon != tc->mon)
continue;
if (!(c->tags & c->mon->tagset[c->mon->seltags]))
continue;
if (step == 0 && ((!tc->mon->isoverview &&
!client_is_in_same_stack(tc, c, NULL)) ||
c->mon != tc->mon))
continue;
int32_t c_l = c->geom.x;
int32_t c_r = c->geom.x + c->geom.width;
int32_t c_t = c->geom.y;
int32_t c_b = c->geom.y + c->geom.height;
int32_t c_cx = c_l + c->geom.width / 2;
int32_t c_cy = c_t + c->geom.height / 2;
int64_t main_dist = 0;
int64_t orth_dist = 0;
bool match_dir = false;
switch (arg->i) {
case UP:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y < sel_y &&
tempClients[_i]->geom.x == sel_x &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y < sel_y &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y < sel_y) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
break;
case DOWN:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y > sel_y &&
tempClients[_i]->geom.x == sel_x &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y > sel_y &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y > sel_y) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
break;
case LEFT:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x < sel_x &&
tempClients[_i]->geom.y == sel_y &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x < sel_x &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x < sel_x) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
if (c_cx < tc_cx || (c_cx == tc_cx && c_l < tc_l)) {
match_dir = true;
main_dist = tc_l - c_r;
orth_dist = (c_b < tc_t)
? (tc_t - c_b)
: ((c_t > tc_b) ? (c_t - tc_b) : 0);
}
break;
case RIGHT:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x > sel_x &&
tempClients[_i]->geom.y == sel_y &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x > sel_x &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x > sel_x) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
if (c_cx > tc_cx || (c_cx == tc_cx && c_l > tc_l)) {
match_dir = true;
main_dist = c_l - tc_r;
orth_dist = (c_b < tc_t)
? (tc_t - c_b)
: ((c_t > tc_b) ? (c_t - tc_b) : 0);
}
break;
case UP:
if (c_cy < tc_cy || (c_cy == tc_cy && c_t < tc_t)) {
match_dir = true;
main_dist = tc_t - c_b;
orth_dist = (c_r < tc_l)
? (tc_l - c_r)
: ((c_l > tc_r) ? (c_l - tc_r) : 0);
}
break;
case DOWN:
if (c_cy > tc_cy || (c_cy == tc_cy && c_t > tc_t)) {
match_dir = true;
main_dist = c_t - tc_b;
orth_dist = (c_r < tc_l)
? (tc_l - c_r)
: ((c_l > tc_r) ? (c_l - tc_r) : 0);
}
break;
default:
continue;
}
free(tempClients); // 释放内存
if (tempSameMonitorFocusClients) {
return tempSameMonitorFocusClients;
} else {
return tempFocusClients;
if (!match_dir)
continue;
int64_t penalty = 0;
if (main_dist < 0) {
penalty = 10000000000LL; // 主方向重叠(反方向)的极大惩罚
main_dist = -main_dist;
}
// 正交方向无重叠惩罚,优先选择在同一行/列的窗口
int64_t no_overlap_penalty = 0;
if (orth_dist > 0) {
// LEFT/RIGHT 时 orth_dist 是垂直间距,>0 表示垂直无重叠
// UP/DOWN 时 orth_dist 是水平间距,>0 表示水平无重叠
no_overlap_penalty = 10000000LL;
}
int64_t tmp_distance = penalty + no_overlap_penalty +
(main_dist * main_dist) +
(orth_dist * orth_dist);
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = c;
}
if (c->mon == tc->mon && tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = c;
}
}
}
if (tempSameMonitorFocusClients)
return tempSameMonitorFocusClients;
return tempFocusClients;
}
Client *direction_select(const Arg *arg) {
@ -462,10 +301,7 @@ Client *direction_select(const Arg *arg) {
return NULL;
}
return find_client_by_direction(
tc, arg, true,
(is_scroller_layout(selmon) || is_centertile_layout(selmon)) &&
!selmon->isoverview);
return find_client_by_direction(tc, arg, true);
}
/* We probably should change the name of this, it sounds like

View file

@ -160,11 +160,26 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
if (pl)
*pl = l;
if (selmon && selmon->isoverview && (!l || layer_ignores_focus(l))) {
if (selmon && selmon->isoverview && config.ov_no_resize) {
ovc = xytoclient(x, y);
bool is_below = false;
if (l && l->layer_surface) {
is_below = (l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ||
l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM);
}
if (ovc && (!l || layer_ignores_focus(l) || is_below)) {
if (pc)
*pc = ovc;
if (psurface && ovc)
*psurface = client_surface(ovc);
if (psurface)
*psurface = ovc ? client_surface(ovc) : NULL;
if (pl && ovc)
*pl = NULL;
}
}
}

View file

@ -25,6 +25,16 @@ void set_size_per(Monitor *m, Client *c) {
c->master_inner_per = 1.0f;
c->stack_inner_per = 1.0f;
}
if (!c->iscustom_scroller_proportion) {
c->scroller_proportion =
m->pertag->scroller_default_proportion[m->pertag->curtag];
}
if (!c->iscustom_scroller_proportion_single) {
c->scroller_proportion_single =
m->pertag->scroller_default_proportion_single[m->pertag->curtag];
}
}
void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
@ -751,6 +761,7 @@ void resize_tile_grid_fair(Client *grabc, bool isdrag, int32_t offsetx,
void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, bool isvertical) {
if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen)
return;
if (grabc->mon->isoverview)
@ -772,7 +783,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
Client *stack_head_client = headnode->client;
if (m->visible_tiling_clients == 1 &&
if (m->visible_scroll_tiling_clients == 1 &&
!config.scroller_ignore_proportion_single)
return;
@ -1212,6 +1223,10 @@ arrange(Monitor *m, bool want_animation, bool from_view) {
if (!m->wlr_output->enabled)
return;
if (!m->sel) {
m->sel = focustop(m);
}
pre_caculate_before_arrange(m, want_animation, from_view, false);
if (m->isoverview) {

View file

@ -565,6 +565,7 @@ void dwindle(Monitor *m) {
break;
}
// 清理树中已不存在的客户端
{
DwindleNode *leaves[512];
int32_t lc = 0;
@ -602,9 +603,14 @@ void dwindle(Monitor *m) {
}
}
// 获得焦点客户端,若为空则用第一个可见平铺客户端兜底
Client *focused = focustop(m);
if (focused && !dwindle_find_leaf(*root, focused))
focused = m->sel;
if (!focused && count > 0)
focused = vis[0];
for (int32_t i = 0; i < count; i++) {
if (!dwindle_find_leaf(*root, vis[i]))
dwindle_insert_with_config(root, vis[i], focused, ratio);

View file

@ -500,16 +500,13 @@ void deck(Monitor *m) {
return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
break;
}
// Calculate master width using mfact from pertag
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
// Calculate master width including outer gaps
if (n > nmasters)
mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0;
else
@ -521,16 +518,15 @@ void deck(Monitor *m) {
continue;
if (i < nmasters) {
c->master_mfact_per = mfact;
// Master area clients
client_tile_resize(
c,
int32_t h =
(m->w.height - 2 * cur_gappov - my) / (MIN(n, nmasters) - i);
client_tile_resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + cur_gappov + my,
.width = mw,
.height = (m->w.height - 2 * cur_gappov - my) /
(MIN(n, nmasters) - i)},
.height = h},
0);
my += c->geom.height;
my += h;
} else {
// Stack area clients
c->master_mfact_per = mfact;
@ -588,6 +584,7 @@ void grid(Monitor *m) {
int32_t target_gappi = enablegaps ? config.gappih : 0;
float single_width_ratio = 0.9;
float single_height_ratio = 0.9;
struct wlr_box target_geom;
n = m->visible_fake_tiling_clients;
@ -603,11 +600,11 @@ void grid(Monitor *m) {
ISFAKETILED(c))) {
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
c->geom.x = m->w.x + (m->w.width - cw) / 2;
c->geom.y = m->w.y + (m->w.height - ch) / 2;
c->geom.width = cw;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
target_geom.x = m->w.x + (m->w.width - cw) / 2;
target_geom.y = m->w.y + (m->w.height - ch) / 2;
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
return;
}
}
@ -651,16 +648,16 @@ void grid(Monitor *m) {
cw = avail_w * (col_pers[i] / sum_col);
if (i == 0) {
c->geom.x = m->w.x + target_gappo;
target_geom.x = m->w.x + target_gappo;
} else if (i == 1) {
// 第二个窗口的 X 坐标紧跟第一个窗口后面
float cw0 = avail_w * (col_pers[0] / sum_col);
c->geom.x = m->w.x + target_gappo + cw0 + target_gappi;
target_geom.x = m->w.x + target_gappo + cw0 + target_gappi;
}
c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
c->geom.width = cw;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
target_geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
i++;
}
}
@ -757,11 +754,11 @@ void grid(Monitor *m) {
? (m->w.y + m->w.height - target_gappo - fl_cy)
: avail_h * (row_pers[r_idx] / sum_row);
c->geom.x = (int32_t)fl_cx;
c->geom.y = (int32_t)fl_cy;
c->geom.width = (int32_t)fl_cw;
c->geom.height = (int32_t)fl_ch;
client_tile_resize(c, c->geom, 0);
target_geom.x = (int32_t)fl_cx;
target_geom.y = (int32_t)fl_cy;
target_geom.width = (int32_t)fl_cw;
target_geom.height = (int32_t)fl_ch;
client_tile_resize(c, target_geom, 0);
i++;
}
}

View file

@ -353,10 +353,65 @@ void overview_resize(Monitor *m) {
free(c_arr);
}
void create_jump_hints(Monitor *m) {
const char jump_labels[] = "HJKLASDFGQWERTYUIOPZXCVBNM";
int label_idx = 0;
Client *c;
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m) &&
((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) {
if (label_idx >= 26)
break;
char c_char = jump_labels[label_idx];
c->jump_char = c_char;
// 把字符变成字符串
char label_text[2] = {c_char, '\0'};
mango_text_node_update(c->text_node, label_text, 1.0f);
wlr_scene_node_set_enabled(&c->text_node->scene_buffer->node, true);
wlr_scene_node_raise_to_top(&c->text_node->scene_buffer->node);
wlr_scene_node_set_position(
&c->text_node->scene_buffer->node,
c->geom.width / 2 - c->text_node->logical_width / 2,
c->geom.height / 2 - c->text_node->logical_height / 2);
label_idx++;
}
}
}
void begin_jump_mode(Monitor *m) { m->is_jump_mode = 1; }
void finish_jump_mode(Monitor *m) {
Client *c = NULL;
if (!m->is_jump_mode) {
return;
}
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m)) {
if (c->text_node->scene_buffer->node.enabled) {
c->jump_char = '\0';
wlr_scene_node_set_enabled(&c->text_node->scene_buffer->node,
false);
}
}
}
m->is_jump_mode = 0;
}
void overview(Monitor *m) {
if (config.ov_no_resize) {
overview_scale(m);
} else {
overview_resize(m);
}
if (m->is_jump_mode) {
create_jump_hints(m);
}
}

View file

@ -284,6 +284,10 @@ void scroller(Monitor *m) {
uint32_t tag = m->pertag->curtag;
struct TagScrollerState *st = ensure_scroller_state(m, tag);
Client *c = NULL;
float scroller_default_proportion_single =
m->pertag->scroller_default_proportion_single[tag];
int32_t scroller_ignore_proportion_single =
m->pertag->scroller_ignore_proportion_single[tag];
/* 按全局客户端链表顺序收集所有堆叠头,确保视觉顺序正确 */
struct ScrollerStackNode *heads[64];
@ -323,14 +327,13 @@ void scroller(Monitor *m) {
m->w.width - 2 * config.scroller_structs - cur_gappih;
/* 单客户端特例 */
if (n_heads == 1 && !config.scroller_ignore_proportion_single &&
if (n_heads == 1 && !scroller_ignore_proportion_single &&
!heads[0]->client->isfullscreen &&
!heads[0]->client->ismaximizescreen) {
struct ScrollerStackNode *head = heads[0];
float single_proportion =
head->scroller_proportion_single > 0.0f
float single_proportion = head->scroller_proportion_single > 0.0f
? head->scroller_proportion_single
: config.scroller_default_proportion_single;
: scroller_default_proportion_single;
struct wlr_box target_geom;
target_geom.height = m->w.height - 2 * cur_gappov;
target_geom.width = (m->w.width - 2 * cur_gappoh) * single_proportion;
@ -420,7 +423,7 @@ void scroller(Monitor *m) {
max_client_width) >
m->w.width - 2 * config.scroller_structs - cur_gappih)));
if (n_heads == 1 && config.scroller_ignore_proportion_single) {
if (n_heads == 1 && scroller_ignore_proportion_single) {
need_scroller = true;
}
if (start_drag_window)
@ -507,6 +510,10 @@ void vertical_scroller(Monitor *m) {
uint32_t tag = m->pertag->curtag;
struct TagScrollerState *st = ensure_scroller_state(m, tag);
Client *c = NULL;
float scroller_default_proportion_single =
m->pertag->scroller_default_proportion_single[tag];
int32_t scroller_ignore_proportion_single =
m->pertag->scroller_ignore_proportion_single[tag];
/* 按全局顺序收集堆叠头 */
struct ScrollerStackNode *heads[64];
@ -542,14 +549,13 @@ void vertical_scroller(Monitor *m) {
int32_t max_client_height =
m->w.height - 2 * config.scroller_structs - cur_gappiv;
if (n_heads == 1 && !config.scroller_ignore_proportion_single &&
if (n_heads == 1 && !scroller_ignore_proportion_single &&
!heads[0]->client->isfullscreen &&
!heads[0]->client->ismaximizescreen) {
struct ScrollerStackNode *head = heads[0];
float single_proportion =
head->scroller_proportion_single > 0.0f
float single_proportion = head->scroller_proportion_single > 0.0f
? head->scroller_proportion_single
: config.scroller_default_proportion_single;
: scroller_default_proportion_single;
struct wlr_box target_geom;
target_geom.width = m->w.width - 2 * cur_gappoh;
target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion;
@ -638,7 +644,7 @@ void vertical_scroller(Monitor *m) {
max_client_height) >
m->w.height - 2 * config.scroller_structs - cur_gappiv)));
if (n_heads == 1 && config.scroller_ignore_proportion_single) {
if (n_heads == 1 && scroller_ignore_proportion_single) {
need_scroller = true;
}
if (start_drag_window)
@ -743,9 +749,9 @@ void scroller_insert_stack(Client *c, Client *target_client,
return;
if (c->isfullscreen)
setfullscreen(c, 0);
setfullscreen(c, 0, true);
if (c->ismaximizescreen)
setmaximizescreen(c, 0);
setmaximizescreen(c, 0, true);
Monitor *m = c->mon;
uint32_t tag = m->pertag->curtag;
@ -785,9 +791,9 @@ void scroller_insert_stack(Client *c, Client *target_client,
head = head->prev_in_stack;
Client *stack_head = head->client;
if (stack_head->ismaximizescreen)
setmaximizescreen(stack_head, 0);
setmaximizescreen(stack_head, 0, true);
if (stack_head->isfullscreen)
setfullscreen(stack_head, 0);
setfullscreen(stack_head, 0, true);
/* 同步到 Client 字段 */
sync_scroller_state_to_clients(m, tag);

View file

@ -137,12 +137,10 @@ void vertical_deck(Monitor *m) {
return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
break;
}
// Calculate master width using mfact from pertag
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
@ -156,16 +154,18 @@ void vertical_deck(Monitor *m) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue;
if (i < nmasters) {
client_tile_resize(
c,
c->master_mfact_per = mfact;
int32_t w =
(m->w.width - 2 * cur_gappoh - mx) / (MIN(n, nmasters) - i);
client_tile_resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh + mx,
.y = m->w.y + cur_gappov,
.width = (m->w.width - 2 * cur_gappoh - mx) /
(MIN(n, nmasters) - i),
.width = w,
.height = mh},
0);
mx += c->geom.width;
mx += w;
} else {
c->master_mfact_per = mfact;
client_tile_resize(
c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
@ -186,14 +186,13 @@ void vertical_grid(Monitor *m) {
int32_t cw, ch;
int32_t rows, cols, overrows;
Client *c = NULL;
int32_t target_gappo =
enablegaps ? m->isoverview ? config.overviewgappo : config.gappov : 0;
int32_t target_gappi =
enablegaps ? m->isoverview ? config.overviewgappi : config.gappiv : 0;
float single_width_ratio = m->isoverview ? 0.7 : 0.9;
float single_height_ratio = m->isoverview ? 0.8 : 0.9;
int32_t target_gappo = enablegaps ? config.gappov : 0;
int32_t target_gappi = enablegaps ? config.gappiv : 0;
float single_width_ratio = 0.9;
float single_height_ratio = 0.9;
struct wlr_box target_geom;
n = m->isoverview ? m->visible_clients : m->visible_fake_tiling_clients;
n = m->visible_fake_tiling_clients;
if (n == 0)
return;
@ -202,15 +201,14 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_is_x11_popup(c)) ||
ISFAKETILED(c))) {
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
c->geom.x = m->w.x + (m->w.width - cw) / 2;
c->geom.y = m->w.y + (m->w.height - ch) / 2;
c->geom.width = cw;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
target_geom.x = m->w.x + (m->w.width - cw) / 2;
target_geom.y = m->w.y + (m->w.height - ch) / 2;
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
return;
}
}
@ -224,8 +222,7 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_is_x11_popup(c)) ||
ISFAKETILED(c))) {
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
if (i < 2)
row_pers[i] =
(c->grid_row_per > 0.0f) ? c->grid_row_per : 1.0f;
@ -242,8 +239,7 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_is_x11_popup(c)) ||
ISFAKETILED(c))) {
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
c->grid_col_idx = 0;
c->grid_row_idx = i;
c->grid_col_per = 1.0f;
@ -252,17 +248,17 @@ void vertical_grid(Monitor *m) {
// 根据分配的权重动态计算当前窗口的高度
ch = avail_h * (row_pers[i] / sum_row);
c->geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
target_geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
if (i == 0) {
c->geom.y = m->w.y + target_gappo;
target_geom.y = m->w.y + target_gappo;
} else if (i == 1) {
// 第二个窗口的 Y 坐标紧跟第一个窗口下面
float ch0 = avail_h * (row_pers[0] / sum_row);
c->geom.y = m->w.y + target_gappo + ch0 + target_gappi;
target_geom.y = m->w.y + target_gappo + ch0 + target_gappi;
}
c->geom.width = cw;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
i++;
}
}
@ -287,7 +283,7 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_is_x11_popup(c)) || ISFAKETILED(c))) {
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
int32_t c_idx = i / rows;
int32_t r_idx = i % rows;
if (r_idx == 0)
@ -314,7 +310,7 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_is_x11_popup(c)) || ISFAKETILED(c))) {
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
int32_t c_idx = i / rows;
int32_t r_idx = i % rows;
@ -352,11 +348,11 @@ void vertical_grid(Monitor *m) {
? (m->w.x + m->w.width - target_gappo - fl_cx)
: avail_w * (col_pers[c_idx] / sum_col);
c->geom.x = (int32_t)fl_cx;
c->geom.y = (int32_t)fl_cy;
c->geom.width = (int32_t)fl_cw;
c->geom.height = (int32_t)fl_ch;
client_tile_resize(c, c->geom, 0);
target_geom.x = (int32_t)fl_cx;
target_geom.y = (int32_t)fl_cy;
target_geom.width = (int32_t)fl_cw;
target_geom.height = (int32_t)fl_ch;
client_tile_resize(c, target_geom, 0);
i++;
}
}

View file

@ -96,6 +96,7 @@
#include <xcb/xcb_icccm.h>
#endif
#include "common/util.h"
#include "draw/text-node.h"
/* macros */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
@ -327,6 +328,7 @@ struct Client {
struct wlr_scene_shadow *shadow;
struct wlr_scene_tree *scene_surface;
struct wlr_scene_tree *overview_scene_surface;
struct mango_text_node *text_node;
struct wl_list link;
struct wl_list flink;
struct wl_list fadeout_link;
@ -381,6 +383,8 @@ struct Client {
int32_t is_in_scratchpad;
int32_t iscustomsize;
int32_t iscustompos;
int32_t iscustom_scroller_proportion;
int32_t iscustom_scroller_proportion_single;
int32_t is_scratchpad_show;
int32_t isglobal;
int32_t isnoborder;
@ -431,6 +435,7 @@ struct Client {
int32_t allow_shortcuts_inhibit;
float scroller_proportion_single;
bool isfocusing;
char jump_char;
bool enable_drop_area_draw;
int32_t drop_direction;
struct wlr_box drag_tile_float_backup_geom;
@ -552,6 +557,7 @@ struct Monitor {
uint32_t ovbk_prev_tagset;
Client *sel, *prevsel;
int32_t isoverview;
int32_t is_jump_mode;
int32_t is_in_hotarea;
int32_t asleep;
uint32_t visible_clients;
@ -735,8 +741,9 @@ static void run(char *startup_cmd);
static void setcursor(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int32_t floating);
static void setfakefullscreen(Client *c, int32_t fakefullscreen);
static void setfullscreen(Client *c, int32_t fullscreen);
static void setmaximizescreen(Client *c, int32_t maximizescreen);
static void setfullscreen(Client *c, int32_t fullscreen, bool rearrange);
static void setmaximizescreen(Client *c, int32_t maximizescreen,
bool rearrange);
static void reset_maximizescreen_size(Client *c);
static void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv);
@ -855,7 +862,7 @@ static float *get_border_color(Client *c);
static void clear_fullscreen_and_maximized_state(Monitor *m);
static void request_fresh_all_monitors(void);
static Client *find_client_by_direction(Client *tc, const Arg *arg,
bool findfloating, bool ignore_align);
bool findfloating);
static void exit_scroller_stack(Client *c);
static Client *scroll_get_stack_head_client(Client *c);
static bool client_only_in_one_tag(Client *c);
@ -896,6 +903,10 @@ Client *scroll_get_stack_tail_client(Client *c);
static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c);
static void overview_backup_surface(Client *c);
static void create_jump_hints(Monitor *m);
static void finish_jump_mode(Monitor *m);
static void begin_jump_mode(Monitor *m);
#include "data/static_keymap.h"
#include "dispatch/bind_declare.h"
#include "layout/layout.h"
@ -1026,6 +1037,9 @@ struct Pertag {
int32_t no_hide[LENGTH(tags) + 1];
int32_t no_render_border[LENGTH(tags) + 1];
int32_t open_as_floating[LENGTH(tags) + 1];
float scroller_default_proportion[LENGTH(tags) + 1];
float scroller_default_proportion_single[LENGTH(tags) + 1];
int32_t scroller_ignore_proportion_single[LENGTH(tags) + 1];
struct DwindleNode *dwindle_root[LENGTH(tags) + 1];
const Layout *ltidxs[LENGTH(tags) + 1];
struct TagScrollerState *scroller_state[LENGTH(tags) + 1];
@ -1073,7 +1087,7 @@ static struct wl_listener last_cursor_surface_destroy_listener = {
.notify = last_cursor_surface_destroy};
#ifdef XWAYLAND
static void fix_xwayland_unmanaged_coordinate(Client *c);
static void fix_xwayland_coordinate(struct wlr_box *geom);
static int32_t synckeymap(void *data);
static void activatex11(struct wl_listener *listener, void *data);
static void configurex11(struct wl_listener *listener, void *data);
@ -1150,11 +1164,11 @@ void clear_fullscreen_flag(Client *c) {
}
if (c->isfullscreen) {
setfullscreen(c, false);
setfullscreen(c, false, true);
}
if (c->ismaximizescreen) {
setmaximizescreen(c, 0);
setmaximizescreen(c, 0, true);
}
}
@ -1615,7 +1629,7 @@ void applyrules(Client *c) {
#ifdef XWAYLAND
if (c->isfloating && client_is_x11(c)) {
fix_xwayland_unmanaged_coordinate(c);
fix_xwayland_coordinate(&c->geom);
c->float_geom = c->geom;
}
#endif
@ -1654,6 +1668,14 @@ void applyrules(Client *c) {
c->isfloating = 1;
}
if (r->scroller_proportion > 0.0f) {
c->iscustom_scroller_proportion = 1;
}
if (r->scroller_proportion_single > 0.0f) {
c->iscustom_scroller_proportion_single = 1;
}
// set geometry of floating client
if (r->width > 1)
@ -1748,7 +1770,7 @@ void applyrules(Client *c) {
view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true);
}
setfullscreen(c, fullscreen_state_backup);
setfullscreen(c, fullscreen_state_backup, true);
if (c->isfakefullscreen) {
setfakefullscreen(c, 1);
@ -2202,9 +2224,10 @@ void hold_end(struct wl_listener *listener, void *data) {
Client *find_closest_tiled_client(Client *c) {
Client *tc, *closest = NULL;
long min_dist = LONG_MAX;
Monitor *cursor_mon = xytomon(cursor->x, cursor->y);
wl_list_for_each(tc, &clients, link) {
if (tc == c || !ISTILED(tc) || !VISIBLEON(tc, c->mon))
if (tc == c || !ISTILED(tc) || !VISIBLEON(tc, cursor_mon))
continue;
if (cursor->x >= tc->geom.x &&
@ -2236,7 +2259,9 @@ void place_drag_tile_client(Client *c) {
if (closest->drop_direction == UNDIR) {
setfloating(c, 0);
exchange_two_client(c, closest);
wl_list_remove(&c->link);
wl_list_insert(closest->link.prev, &c->link);
arrange(closest->mon, false, false);
return;
}
@ -2335,6 +2360,17 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
}
}
// overview模式下鼠标左键跳转右键关闭窗口
if (selmon && selmon->isoverview && event->button == BTN_LEFT && c) {
toggleoverview(&(Arg){.i = 1});
return true;
}
if (selmon && selmon->isoverview && event->button == BTN_RIGHT && c) {
pending_kill_client(c);
return true;
}
// 当鼠标焦点在layer上的时候不检测虚拟键盘的mod状态
// 避免layer虚拟键盘锁死mod按键状态
hard_keyboard = &kb_group->wlr_group->keyboard;
@ -2351,16 +2387,6 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
break;
m = &config.mouse_bindings[ji];
if (selmon->isoverview && event->button == BTN_LEFT && c) {
toggleoverview(&(Arg){.i = 1});
return true;
}
if (selmon->isoverview && event->button == BTN_RIGHT && c) {
pending_kill_client(c);
return true;
}
if (CLEANMASK(mods) == CLEANMASK(m->mod) &&
event->button == m->button && m->func &&
(CLEANMASK(m->mod) != 0 ||
@ -2543,6 +2569,8 @@ void cleanup(void) {
/* Destroy after the wayland display (when the monitors are already
destroyed) to avoid destroying them with an invalid scene output. */
wlr_scene_node_destroy(&scene->tree.node);
mango_text_global_finish();
}
void cleanupmon(struct wl_listener *listener, void *data) {
@ -3140,7 +3168,6 @@ void createlayersurface(struct wl_listener *listener, void *data) {
LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify);
wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link);
wlr_surface_send_enter(surface, layer_surface->output);
}
void createlocksurface(struct wl_listener *listener, void *data) {
@ -3940,7 +3967,7 @@ fullscreennotify(struct wl_listener *listener, void *data) {
if (!c || c->iskilling)
return;
setfullscreen(c, client_wants_fullscreen(c));
setfullscreen(c, client_wants_fullscreen(c), true);
}
void requestmonstate(struct wl_listener *listener, void *data) {
@ -4206,6 +4233,11 @@ void keypress(struct wl_listener *listener, void *data) {
}
}
if (config.cursor_hide_on_keypress && !cursor_hidden &&
event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
hidecursor(NULL);
}
/* On _press_ if there is no active screen locker,
* attempt to process a compositor keybinding. */
for (i = 0; i < nsyms; i++)
@ -4232,6 +4264,27 @@ void keypress(struct wl_listener *listener, void *data) {
if (handled)
return;
if (selmon && selmon->is_jump_mode &&
event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
for (i = 0; i < nsyms; i++) {
xkb_keysym_t sym = xkb_keysym_to_lower(syms[i]);
if (sym >= XKB_KEY_a && sym <= XKB_KEY_z) {
char c_char = 'A' + (sym - XKB_KEY_a);
Client *c;
wl_list_for_each(c, &clients, link) {
if (c->mon == selmon && c->jump_char == c_char) {
focusclient(c, 1);
toggleoverview(&(Arg){.i = 1});
return;
}
}
} else if (sym == XKB_KEY_Escape) {
togglejump(&(Arg){.i = 0});
return;
}
}
}
/* don't pass when popup is focused
* this is better than having popups (like fuzzel or wmenu) closing
* while typing in a passed keybind */
@ -4399,6 +4452,8 @@ void init_client_properties(Client *c) {
c->ignore_minimize = 1;
c->iscustomsize = 0;
c->iscustompos = 0;
c->iscustom_scroller_proportion = 0;
c->iscustom_scroller_proportion_single = 0;
c->master_mfact_per = 0.0f;
c->master_inner_per = 0.0f;
c->stack_inner_per = 0.0f;
@ -4469,26 +4524,30 @@ mapnotify(struct wl_listener *listener, void *data) {
/* Handle unmanaged clients first so we can return prior create borders
*/
#ifdef XWAYLAND
if (client_is_unmanaged(c)) {
/* Unmanaged clients always are floating */
#ifdef XWAYLAND
if (client_is_x11(c)) {
fix_xwayland_unmanaged_coordinate(c);
fix_xwayland_coordinate(&c->geom);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x,
c->geom.y, c->geom.width,
c->geom.height);
LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry,
setgeometrynotify);
}
#endif
wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
if (client_wants_focus(c)) {
focusclient(c, 1);
exclusive_focus = c;
}
return;
}
#endif
// extra node
c->text_node = mango_text_node_create(c->scene, config.jumhitdata);
wlr_scene_node_lower_to_bottom(&c->text_node->scene_buffer->node);
wlr_scene_node_set_enabled(&c->text_node->scene_buffer->node, false);
for (i = 0; i < 2; i++) {
c->splitindicator[i] = wlr_scene_rect_create(
c->scene, 0, 0,
@ -4578,9 +4637,9 @@ void maximizenotify(struct wl_listener *listener, void *data) {
}
if (client_request_maximize(c, data)) {
setmaximizescreen(c, 1);
setmaximizescreen(c, 1, true);
} else {
setmaximizescreen(c, 0);
setmaximizescreen(c, 0, true);
}
}
@ -4808,7 +4867,8 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
if (!surface && !seat->drag && !cursor_hidden)
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
if (c && c->mon && !c->animation.running && (INSIDEMON(c) || !ISTILED(c))) {
if (c && c->mon && !c->animation.running &&
(INSIDEMON(c) || !ISSCROLLTILED(c))) {
scroller_focus_lock = 0;
}
@ -4820,13 +4880,15 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
}
if (!scroller_focus_lock || !(c && c->mon && !INSIDEMON(c))) {
if (c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c)) {
if (c && c->mon && ISSCROLLTILED(c) && is_scroller_layout(c->mon) &&
!INSIDEMON(c)) {
should_lock = true;
}
if (!((!config.edge_scroller_pointer_focus ||
speed < config.edge_scroller_focus_allow_speed) &&
c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c))) {
c && c->mon && ISSCROLLTILED(c) && is_scroller_layout(c->mon) &&
!INSIDEMON(c))) {
pointerfocus(c, surface, sx, sy, time);
}
@ -5442,7 +5504,7 @@ void exit_scroller_stack(Client *c) {
}
}
void setmaximizescreen(Client *c, int32_t maximizescreen) {
void setmaximizescreen(Client *c, int32_t maximizescreen, bool rearrange) {
struct wlr_box maximizescreen_box;
if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling)
return;
@ -5483,6 +5545,7 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
client_set_maximized(c, true);
}
if (rearrange)
arrange(c->mon, false, false);
}
@ -5492,12 +5555,13 @@ void setfakefullscreen(Client *c, int32_t fakefullscreen) {
return;
if (c->isfullscreen)
setfullscreen(c, 0);
setfullscreen(c, 0, true);
client_set_fullscreen(c, fakefullscreen);
}
void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自带全屏
void setfullscreen(Client *c, int32_t fullscreen,
bool rearrange) // 用自定义全屏代理自带全屏
{
if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling)
@ -5543,6 +5607,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
layers[fullscreen || c->isfloating ? LyrTop : LyrTile]);
}
if (rearrange)
arrange(c->mon, false, false);
}
@ -5672,7 +5737,8 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) {
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) */
setfullscreen(c, c->isfullscreen,
true); /* This will call arrange(c->mon) */
}
if (focus && !client_is_x11_popup(c)) {
@ -6264,13 +6330,13 @@ void overview_restore(Client *c, const Arg *arg) {
resize(c, c->overview_backup_geom, 0);
} else if (c->isfullscreen || c->ismaximizescreen) {
if (want_restore_fullscreen(c) && c->ismaximizescreen) {
setmaximizescreen(c, 1);
setmaximizescreen(c, 1, false);
} else if (want_restore_fullscreen(c) && c->isfullscreen) {
setfullscreen(c, 1);
setfullscreen(c, 1, false);
} else {
client_pending_fullscreen_state(c, 0);
client_pending_maximized_state(c, 0);
setfullscreen(c, false);
setfullscreen(c, false, false);
}
} else {
if (c->is_restoring_from_ov) {
@ -6466,8 +6532,8 @@ void unmapnotify(struct wl_listener *listener, void *data) {
}
if (c->swallowedby) {
setmaximizescreen(c->swallowedby, c->ismaximizescreen);
setfullscreen(c->swallowedby, c->isfullscreen);
setmaximizescreen(c->swallowedby, c->ismaximizescreen, true);
setfullscreen(c->swallowedby, c->isfullscreen, true);
c->swallowedby->swallowing = NULL;
c->swallowedby = NULL;
}
@ -6479,6 +6545,7 @@ void unmapnotify(struct wl_listener *listener, void *data) {
c->stack_proportion = 0.0f;
mango_text_node_destroy(c->text_node);
wlr_scene_node_destroy(&c->scene->node);
printstatus(IPC_WATCH_ARRANGGE);
motionnotify(0, NULL, 0, 0, 0, 0);
@ -6825,16 +6892,17 @@ void virtualpointer(struct wl_listener *listener, void *data) {
}
#ifdef XWAYLAND
void fix_xwayland_unmanaged_coordinate(Client *c) {
void fix_xwayland_coordinate(struct wlr_box *geom) {
if (!selmon)
return;
// 1. 如果窗口已经在当前活动显示器内,直接返回
if (c->geom.x >= selmon->m.x && c->geom.x < selmon->m.x + selmon->m.width &&
c->geom.y >= selmon->m.y && c->geom.y < selmon->m.y + selmon->m.height)
if (geom->x >= selmon->m.x && geom->x <= selmon->m.x + selmon->m.width &&
geom->y >= selmon->m.y && geom->y <= selmon->m.y + selmon->m.height)
return;
c->geom = setclient_coordinate_center(c, selmon, c->geom, 0, 0);
geom->x = selmon->m.x + (selmon->m.width - geom->width) / 2;
geom->y = selmon->m.y + (selmon->m.height - geom->height) / 2;
}
int32_t synckeymap(void *data) {
@ -6889,24 +6957,41 @@ void activatex11(struct wl_listener *listener, void *data) {
void configurex11(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, configure);
struct wlr_xwayland_surface_configure_event *event = data;
struct wlr_box new_geo;
new_geo.x = event->x;
new_geo.y = event->y;
new_geo.width = event->width;
new_geo.height = event->height;
fix_xwayland_coordinate(&new_geo);
if (!client_surface(c) || !client_surface(c)->mapped) {
wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y,
event->width, event->height);
wlr_xwayland_surface_configure(c->surface.xwayland, new_geo.x,
new_geo.y, new_geo.width,
new_geo.height);
return;
}
if (client_is_unmanaged(c)) {
wlr_scene_node_set_position(&c->scene->node, event->x, event->y);
wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y,
event->width, event->height);
wlr_scene_node_set_position(&c->scene->node, new_geo.x, new_geo.y);
wlr_xwayland_surface_configure(c->surface.xwayland, new_geo.x,
new_geo.y, new_geo.width,
new_geo.height);
return;
}
if ((c->isfloating && c != grabc) ||
!c->mon->pertag->ltidxs[c->mon->pertag->curtag]->arrange) {
if (c->isfloating && c != grabc) {
new_geo.x = new_geo.x - c->bw;
new_geo.y = new_geo.y - c->bw;
new_geo.width = new_geo.width + c->bw * 2;
new_geo.height = new_geo.height + c->bw * 2;
fix_xwayland_coordinate(&new_geo);
resize(c,
(struct wlr_box){.x = event->x - c->bw,
.y = event->y - c->bw,
.width = event->width + c->bw * 2,
.height = event->height + c->bw * 2},
(struct wlr_box){.x = new_geo.x,
.y = new_geo.y,
.width = new_geo.width,
.height = new_geo.height},
0);
} else {
arrange(c->mon, false, false);