Merge branch 'mangowm:wl-only' into wl-only

This commit is contained in:
CtrlLuzzio 2026-06-18 20:21:19 -04:00 committed by GitHub
commit 5b58df6650
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 1676 additions and 100 deletions

View file

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

View file

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

View file

@ -52,6 +52,39 @@ You can also color-code windows based on their state:
> **Tip:** For scratchpad window sizing, see [Scratchpad](/docs/window-management/scratchpad) configuration. > **Tip:** For scratchpad window sizing, see [Scratchpad](/docs/window-management/scratchpad) configuration.
### Overview Jump Mode
| Setting | Default | Description |
| :--- | :--- | :--- |
| `jump_label_decorate_fg_color` | `0xc4939dff` | text color. |
| `jump_label_decorate_bg_color` | `0x201b14ff` | background color.|
| `jump_label_decorate_focus_fg_color` | `0x201b14ff` | text color for focus. |
| `jump_label_decorate_focus_bg_color` | `0xc4939dff` | background color for focus.|
| `jump_label_decorate_border_color` | `0x8BAA9Bff` | border color.|
| `jump_label_decorate_border_width` | `4` | border width.|
| `jump_label_decorate_corner_radius` | `5` | corner radius.|
| `jump_label_decorate_padding_x` | `10` | horizontal padding.|
| `jump_label_decorate_padding_y` | `10` | vertical padding.|
| `jump_label_decorate_font_desc` | `monospace Bold 16` | font set.|
### Tab Bar For Monocle Layout
| Setting | Default | Description |
| :--- | :--- | :--- |
| `tab_bar_height` | `50` | Height of the tab bar for monocle layout. |
| `tab_bar_decorate_fg_color` | `0xc4939dff` | text color.
| `tab_bar_decorate_bg_color` | `0x201b14ff` | background color.|
| `tab_bar_decorate_focus_fg_color` | `0x201b14ff` | text color for focus. |
| `tab_bar_decorate_focus_bg_color` | `0xc4939dff` | background color for focus.|
| `tab_bar_decorate_border_color` | `0x8BAA9Bff` | border color.|
| `tab_bar_decorate_border_width` | `4` | border width.|
| `tab_bar_decorate_corner_radius` | `5` | corner radius.|
| `tab_bar_decorate_padding_x` | `0` | horizontal padding.|
| `tab_bar_decorate_padding_y` | `0` | vertical padding.|
| `tab_bar_decorate_font_desc` | `monospace Bold 16` | font set.|
## Borders
Control the appearance of window borders.
## Cursor Theme ## Cursor Theme
Set the size and theme of your mouse cursor. Set the size and theme of your mouse cursor.

View file

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

View file

@ -26,6 +26,7 @@ endif
cc = meson.get_compiler('c') cc = meson.get_compiler('c')
libm = cc.find_library('m') libm = cc.find_library('m')
libdrm = dependency('libdrm')
xcb = dependency('xcb', required : get_option('xwayland')) xcb = dependency('xcb', required : get_option('xwayland'))
xlibs = dependency('xcb-icccm', required : get_option('xwayland')) xlibs = dependency('xcb-icccm', required : get_option('xwayland'))
wlroots_dep = dependency('wlroots-0.20',version: '>=0.20.0') wlroots_dep = dependency('wlroots-0.20',version: '>=0.20.0')
@ -36,6 +37,7 @@ libwayland_client_dep = dependency('wayland-client')
pcre2_dep = dependency('libpcre2-8') pcre2_dep = dependency('libpcre2-8')
pixman_dep = dependency('pixman-1') pixman_dep = dependency('pixman-1')
cjson_dep = dependency('libcjson') cjson_dep = dependency('libcjson')
pangocairo_dep = dependency('pangocairo')
# version info # version info
git = find_program('git', required : false) git = find_program('git', required : false)
@ -93,9 +95,11 @@ endif
executable('mango-wl', executable('mango-wl',
'src/mango.c', 'src/mango.c',
'src/common/util.c', 'src/common/util.c',
'src/draw/text-node.c',
wayland_sources, wayland_sources,
dependencies : [ dependencies : [
libm, libm,
libdrm,
xcb, xcb,
xlibs, xlibs,
wayland_server_dep, wayland_server_dep,
@ -106,6 +110,7 @@ executable('mango-wl',
pcre2_dep, pcre2_dep,
pixman_dep, pixman_dep,
cjson_dep, cjson_dep,
pangocairo_dep,
], ],
install : true, install : true,
c_args : c_args, c_args : c_args,

View file

@ -3,8 +3,10 @@
libX11, libX11,
libinput, libinput,
libxcb, libxcb,
libdrm,
libxkbcommon, libxkbcommon,
pcre2, pcre2,
pango,
cjson, cjson,
pixman, pixman,
pkg-config, pkg-config,
@ -49,6 +51,7 @@ stdenv.mkDerivation {
libxcb libxcb
libxkbcommon libxkbcommon
pcre2 pcre2
pango
cjson cjson
pixman pixman
wayland wayland
@ -56,6 +59,7 @@ stdenv.mkDerivation {
wlroots_0_19 wlroots_0_19
scenefx scenefx
libGL libGL
libdrm
] ]
++ lib.optionals enableXWayland [ ++ lib.optionals enableXWayland [
libX11 libX11

View file

@ -95,4 +95,28 @@ void client_pending_force_kill(Client *c) {
if (!c) if (!c)
return; return;
kill(c->pid, SIGKILL); kill(c->pid, SIGKILL);
} }
void client_add_jump_label_node(Client *c) {
c->jump_label_node =
mango_jump_label_node_create(c->scene, config.jumplabeldata);
wlr_scene_node_lower_to_bottom(&c->jump_label_node->scene_buffer->node);
wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node, false);
}
void client_add_tab_bar_node(Client *c) {
if (config.tab_bar_height <= 0) {
return;
}
MangoNodeData *mangonodedata = ecalloc(1, sizeof(MangoNodeData));
mangonodedata->node_data = c;
mangonodedata->type = MANGO_TITLE_NODE;
c->tab_bar_node = mango_tab_bar_node_create(
mangonodedata, layers[LyrDecorate], config.tabdata, 0, 0);
wlr_scene_node_lower_to_bottom(&c->tab_bar_node->scene_buffer->node);
wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, false);
mango_tab_bar_node_update(c->tab_bar_node, client_get_title(c), 1.0);
}

View file

@ -289,6 +289,20 @@ void apply_shield(Client *c, struct wlr_box clip_box) {
} }
} }
void global_draw_tab_bar(Client *c, int32_t x, int32_t y, int32_t width,
int32_t height) {
if (!c->tab_bar_node)
return;
if (height <= 0) {
wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, false);
}
wlr_scene_node_set_position(&c->tab_bar_node->scene_buffer->node, x, y);
wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, true);
mango_tab_bar_node_set_size(c->tab_bar_node, width, height);
}
void apply_split_border(Client *c, bool hit_no_border) { void apply_split_border(Client *c, bool hit_no_border) {
if (c->iskilling || !c->mon || !client_surface(c)->mapped) if (c->iskilling || !c->mon || !client_surface(c)->mapped)
@ -544,8 +558,10 @@ struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) {
(ISSCROLLTILED(c) || c->animation.tagouting || c->animation.tagining)) { (ISSCROLLTILED(c) || c->animation.tagouting || c->animation.tagining)) {
c->is_clip_to_hide = true; c->is_clip_to_hide = true;
wlr_scene_node_set_enabled(&c->scene->node, false); wlr_scene_node_set_enabled(&c->scene->node, false);
} else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) { } else if (c->is_clip_to_hide && VISIBLEON(c, c->mon) &&
(!c->is_monocle_hide || !is_monocle_layout(c->mon))) {
c->is_clip_to_hide = false; c->is_clip_to_hide = false;
c->is_monocle_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true); wlr_scene_node_set_enabled(&c->scene->node, true);
} }
@ -898,7 +914,7 @@ void fadeout_client_animation_next_tick(Client *c) {
double percent = config.fadeout_begin_opacity - double percent = config.fadeout_begin_opacity -
(opacity_eased_progress * config.fadeout_begin_opacity); (opacity_eased_progress * config.fadeout_begin_opacity);
double opacity = MAX(percent, 0); double opacity = MANGO_MAX(percent, 0);
if (config.animation_fade_out && !c->nofadeout) if (config.animation_fade_out && !c->nofadeout)
wlr_scene_node_for_each_buffer(&c->scene->node, wlr_scene_node_for_each_buffer(&c->scene->node,
@ -1177,8 +1193,8 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
if (is_scroller_layout(c->mon) && (!c->isfloating || c == grabc)) { if (is_scroller_layout(c->mon) && (!c->isfloating || c == grabc)) {
c->geom = geo; c->geom = geo;
c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); c->geom.width = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.width);
c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); c->geom.height = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.height);
} else { // 这里会限制不允许窗口划出屏幕 } else { // 这里会限制不允许窗口划出屏幕
c->geom = geo; c->geom = geo;
applybounds( applybounds(

View file

@ -233,7 +233,7 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) {
double percent = config.fadeout_begin_opacity - double percent = config.fadeout_begin_opacity -
(opacity_eased_progress * config.fadeout_begin_opacity); (opacity_eased_progress * config.fadeout_begin_opacity);
double opacity = MAX(percent, 0.0f); double opacity = MANGO_MAX(percent, 0.0f);
if (config.animation_fade_out) if (config.animation_fade_out)
wlr_scene_node_for_each_buffer(&l->scene->node, wlr_scene_node_for_each_buffer(&l->scene->node,
@ -277,10 +277,10 @@ void layer_animation_next_tick(LayerSurface *l) {
double opacity_eased_progress = double opacity_eased_progress =
find_animation_curve_at(animation_passed, OPAFADEIN); find_animation_curve_at(animation_passed, OPAFADEIN);
double opacity = double opacity = MANGO_MIN(config.fadein_begin_opacity +
MIN(config.fadein_begin_opacity + opacity_eased_progress *
opacity_eased_progress * (1.0 - config.fadein_begin_opacity), (1.0 - config.fadein_begin_opacity),
1.0f); 1.0f);
if (config.animation_fade_in) if (config.animation_fade_in)
wlr_scene_node_for_each_buffer(&l->scene->node, wlr_scene_node_for_each_buffer(&l->scene->node,

View file

@ -23,30 +23,32 @@ void set_tagin_animation(Monitor *m, Client *c) {
c->animainit_geom.x = config.tag_animation_direction == VERTICAL c->animainit_geom.x = config.tag_animation_direction == VERTICAL
? c->animation.current.x ? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width, : MANGO_MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width); c->geom.x + c->mon->m.width);
c->animainit_geom.y = config.tag_animation_direction == VERTICAL c->animainit_geom.y = config.tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height, ? MANGO_MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height) c->geom.y + c->mon->m.height)
: c->animation.current.y; : c->animation.current.y;
} else { } else {
c->animainit_geom.x = c->animainit_geom.x = config.tag_animation_direction == VERTICAL
config.tag_animation_direction == VERTICAL ? c->animation.current.x
? c->animation.current.x : MANGO_MIN(m->m.x - c->geom.width,
: MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width); c->geom.x - c->mon->m.width);
c->animainit_geom.y = c->animainit_geom.y = config.tag_animation_direction == VERTICAL
config.tag_animation_direction == VERTICAL ? MANGO_MIN(m->m.y - c->geom.height,
? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height) c->geom.y - c->mon->m.height)
: c->animation.current.y; : c->animation.current.y;
} }
} }
void set_arrange_visible(Monitor *m, Client *c, bool want_animation) { void set_arrange_visible(Monitor *m, Client *c, bool want_animation) {
if (!c->is_clip_to_hide || !ISTILED(c) || !is_scroller_layout(c->mon)) { if (!ISTILED(c) || ((!c->is_clip_to_hide || !is_scroller_layout(c->mon)) &&
(!c->is_monocle_hide || !is_monocle_layout(c->mon)))) {
c->is_clip_to_hide = false; c->is_clip_to_hide = false;
c->is_monocle_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true); wlr_scene_node_set_enabled(&c->scene->node, true);
wlr_scene_node_set_enabled(&c->scene_surface->node, true); wlr_scene_node_set_enabled(&c->scene_surface->node, true);
} }
@ -84,13 +86,13 @@ void set_tagout_animation(Monitor *m, Client *c) {
: m->pertag->curtag > m->pertag->prevtag; : m->pertag->curtag > m->pertag->prevtag;
if (going_forward) { if (going_forward) {
c->pending = c->geom; c->pending = c->geom;
c->pending.x = c->pending.x = config.tag_animation_direction == VERTICAL
config.tag_animation_direction == VERTICAL ? c->animation.current.x
? c->animation.current.x : MANGO_MIN(c->mon->m.x - c->geom.width,
: MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width); c->geom.x - c->mon->m.width);
c->pending.y = config.tag_animation_direction == VERTICAL c->pending.y = config.tag_animation_direction == VERTICAL
? MIN(c->mon->m.y - c->geom.height, ? MANGO_MIN(c->mon->m.y - c->geom.height,
c->geom.y - c->mon->m.height) c->geom.y - c->mon->m.height)
: c->animation.current.y; : c->animation.current.y;
resize(c, c->geom, 0); resize(c, c->geom, 0);
@ -98,11 +100,11 @@ void set_tagout_animation(Monitor *m, Client *c) {
c->pending = c->geom; c->pending = c->geom;
c->pending.x = config.tag_animation_direction == VERTICAL c->pending.x = config.tag_animation_direction == VERTICAL
? c->animation.current.x ? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width, : MANGO_MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width); c->geom.x + c->mon->m.width);
c->pending.y = config.tag_animation_direction == VERTICAL c->pending.y = config.tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height, ? MANGO_MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height) c->geom.y + c->mon->m.height)
: c->animation.current.y; : c->animation.current.y;
resize(c, c->geom, 0); resize(c, c->geom, 0);
} }

View file

@ -256,6 +256,7 @@ typedef struct {
int32_t enable_hotarea; int32_t enable_hotarea;
int32_t ov_tab_mode; int32_t ov_tab_mode;
int32_t ov_no_resize; int32_t ov_no_resize;
int32_t overviewgappi; int32_t overviewgappi;
int32_t overviewgappo; int32_t overviewgappo;
uint32_t cursor_hide_timeout; uint32_t cursor_hide_timeout;
@ -310,6 +311,7 @@ typedef struct {
uint32_t gappoh; uint32_t gappoh;
uint32_t gappov; uint32_t gappov;
uint32_t borderpx; uint32_t borderpx;
uint32_t tab_bar_height;
float scratchpad_width_ratio; float scratchpad_width_ratio;
float scratchpad_height_ratio; float scratchpad_height_ratio;
float rootcolor[4]; float rootcolor[4];
@ -386,6 +388,8 @@ typedef struct {
struct xkb_context *ctx; struct xkb_context *ctx;
struct xkb_keymap *keymap; struct xkb_keymap *keymap;
DecorateDrawData jumplabeldata;
DecorateDrawData tabdata;
} Config; } Config;
typedef int32_t (*FuncType)(const Arg *); typedef int32_t (*FuncType)(const Arg *);
@ -1009,6 +1013,9 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
} else if (strcmp(func_name, "toggleoverview") == 0) { } else if (strcmp(func_name, "toggleoverview") == 0) {
func = toggleoverview; func = toggleoverview;
(*arg).i = atoi(arg_value); (*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) { } else if (strcmp(func_name, "set_proportion") == 0) {
func = set_proportion; func = set_proportion;
(*arg).f = atof(arg_value); (*arg).f = atof(arg_value);
@ -1701,6 +1708,146 @@ bool parse_option(Config *config, char *key, char *value) {
config->cursor_size = atoi(value); config->cursor_size = atoi(value);
} else if (strcmp(key, "cursor_theme") == 0) { } else if (strcmp(key, "cursor_theme") == 0) {
config->cursor_theme = strdup(value); config->cursor_theme = strdup(value);
} else if (strcmp(key, "tab_bar_decorate_font_desc") == 0) {
config->tabdata.font_desc = strdup(value);
} else if (strcmp(key, "tab_bar_decorate_fg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_fg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.fg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_bg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_bg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.bg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_focus_fg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_focus_fg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.focus_fg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_focus_bg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_focus_bg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.focus_bg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_border_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_border_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.border_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_border_width") == 0) {
config->tabdata.border_width = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "tab_bar_decorate_corner_radius") == 0) {
config->tabdata.corner_radius = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "tab_bar_decorate_padding_x") == 0) {
config->tabdata.padding_x = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "tab_bar_decorate_padding_y") == 0) {
config->tabdata.padding_y = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_label_decorate_font_desc") == 0) {
config->jumplabeldata.font_desc = strdup(value);
} else if (strcmp(key, "jump_label_decorate_fg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"jump_label_decorate_fg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumplabeldata.fg_color, color);
}
} else if (strcmp(key, "jump_label_decorate_bg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"jump_label_decorate_bg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumplabeldata.bg_color, color);
}
} else if (strcmp(key, "jump_label_decorate_focus_fg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"jump_label_decorate_focus_fg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumplabeldata.focus_fg_color, color);
}
} else if (strcmp(key, "jump_label_decorate_focus_bg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"jump_label_decorate_focus_bg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumplabeldata.focus_bg_color, color);
}
} else if (strcmp(key, "jump_label_decorate_border_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"jump_label_decorate_border_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->jumplabeldata.border_color, color);
}
} else if (strcmp(key, "jump_label_decorate_border_width") == 0) {
config->jumplabeldata.border_width = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_label_decorate_corner_radius") == 0) {
config->jumplabeldata.corner_radius = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_label_decorate_padding_x") == 0) {
config->jumplabeldata.padding_x = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_label_decorate_padding_y") == 0) {
config->jumplabeldata.padding_y = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "disable_while_typing") == 0) { } else if (strcmp(key, "disable_while_typing") == 0) {
config->disable_while_typing = atoi(value); config->disable_while_typing = atoi(value);
} else if (strcmp(key, "left_handed") == 0) { } else if (strcmp(key, "left_handed") == 0) {
@ -1747,6 +1894,8 @@ bool parse_option(Config *config, char *key, char *value) {
config->scratchpad_height_ratio = atof(value); config->scratchpad_height_ratio = atof(value);
} else if (strcmp(key, "borderpx") == 0) { } else if (strcmp(key, "borderpx") == 0) {
config->borderpx = atoi(value); config->borderpx = atoi(value);
} else if (strcmp(key, "tab_bar_height") == 0) {
config->tab_bar_height = atoi(value);
} else if (strcmp(key, "rootcolor") == 0) { } else if (strcmp(key, "rootcolor") == 0) {
int64_t color = parse_color(value); int64_t color = parse_color(value);
if (color == -1) { if (color == -1) {
@ -3160,6 +3309,16 @@ void free_config(void) {
config.cursor_theme = NULL; config.cursor_theme = NULL;
} }
if (config.jumplabeldata.font_desc) {
free((void *)config.jumplabeldata.font_desc);
config.jumplabeldata.font_desc = NULL;
}
if (config.tabdata.font_desc) {
free((void *)config.tabdata.font_desc);
config.tabdata.font_desc = NULL;
}
if (config.tablet_map_to_mon) { if (config.tablet_map_to_mon) {
free(config.tablet_map_to_mon); free(config.tablet_map_to_mon);
config.tablet_map_to_mon = NULL; config.tablet_map_to_mon = NULL;
@ -3321,10 +3480,27 @@ void override_config(void) {
config.scratchpad_height_ratio = config.scratchpad_height_ratio =
CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f); CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f);
config.borderpx = CLAMP_INT(config.borderpx, 0, 200); config.borderpx = CLAMP_INT(config.borderpx, 0, 200);
config.tab_bar_height = CLAMP_INT(config.tab_bar_height, 0, 500);
config.smartgaps = CLAMP_INT(config.smartgaps, 0, 1); config.smartgaps = CLAMP_INT(config.smartgaps, 0, 1);
config.focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f); config.focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f);
config.unfocused_opacity = config.unfocused_opacity =
CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f); CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f);
config.tabdata.border_width =
CLAMP_INT(config.tabdata.border_width, 0, 100);
config.tabdata.corner_radius =
CLAMP_INT(config.tabdata.corner_radius, 0, 100);
config.tabdata.padding_x = CLAMP_INT(config.tabdata.padding_x, 0, 100);
config.tabdata.padding_y = CLAMP_INT(config.tabdata.padding_y, 0, 100);
config.jumplabeldata.border_width =
CLAMP_INT(config.jumplabeldata.border_width, 0, 100);
config.jumplabeldata.corner_radius =
CLAMP_INT(config.jumplabeldata.corner_radius, 0, 100);
config.jumplabeldata.padding_x =
CLAMP_INT(config.jumplabeldata.padding_x, 0, 100);
config.jumplabeldata.padding_y =
CLAMP_INT(config.jumplabeldata.padding_y, 0, 100);
} }
void set_value_default() { void set_value_default() {
@ -3363,7 +3539,6 @@ void set_value_default() {
config.log_level = WLR_ERROR; config.log_level = WLR_ERROR;
config.numlockon = 0; config.numlockon = 0;
config.capslock = 0; config.capslock = 0;
config.ov_tab_mode = 1; config.ov_tab_mode = 1;
config.ov_no_resize = 1; config.ov_no_resize = 1;
config.hotarea_size = 10; config.hotarea_size = 10;
@ -3413,6 +3588,7 @@ void set_value_default() {
config.idleinhibit_ignore_visible = 0; config.idleinhibit_ignore_visible = 0;
config.borderpx = 4; config.borderpx = 4;
config.tab_bar_height = 50;
config.overviewgappi = 5; config.overviewgappi = 5;
config.overviewgappo = 30; config.overviewgappo = 30;
config.cursor_hide_timeout = 0; config.cursor_hide_timeout = 0;
@ -3477,6 +3653,56 @@ void set_value_default() {
config.animation_curve_opafadeout[2] = 0.5; config.animation_curve_opafadeout[2] = 0.5;
config.animation_curve_opafadeout[3] = 0.5; config.animation_curve_opafadeout[3] = 0.5;
config.tabdata.fg_color[0] = 0xc4 / 255.0f;
config.tabdata.fg_color[1] = 0x93 / 255.0f;
config.tabdata.fg_color[2] = 0x9d / 255.0f;
config.tabdata.fg_color[3] = 1.0f;
config.tabdata.bg_color[0] = 0x32 / 255.0f;
config.tabdata.bg_color[1] = 0x32 / 255.0f;
config.tabdata.bg_color[2] = 0x32 / 255.0f;
config.tabdata.bg_color[3] = 1.0f;
config.tabdata.focus_fg_color[0] = 0xed / 255.0f;
config.tabdata.focus_fg_color[1] = 0xa6 / 255.0f;
config.tabdata.focus_fg_color[2] = 0xb4 / 255.0f;
config.tabdata.focus_fg_color[3] = 1.0f;
config.tabdata.focus_bg_color[0] = 0x4e / 255.0f;
config.tabdata.focus_bg_color[1] = 0x45 / 255.0f;
config.tabdata.focus_bg_color[2] = 0x3c / 255.0f;
config.tabdata.focus_bg_color[3] = 1.0f;
config.tabdata.border_color[0] = 0x8b / 255.0f;
config.tabdata.border_color[1] = 0xaa / 255.0f;
config.tabdata.border_color[2] = 0x9b / 255.0f;
config.tabdata.border_color[3] = 1.0f;
config.tabdata.border_width = 4;
config.tabdata.corner_radius = 5;
config.tabdata.padding_x = 0;
config.tabdata.padding_y = 0;
config.jumplabeldata.fg_color[0] = 0xc4 / 255.0f;
config.jumplabeldata.fg_color[1] = 0x93 / 255.0f;
config.jumplabeldata.fg_color[2] = 0x9d / 255.0f;
config.jumplabeldata.fg_color[3] = 1.0f;
config.jumplabeldata.bg_color[0] = 0x32 / 255.0f;
config.jumplabeldata.bg_color[1] = 0x32 / 255.0f;
config.jumplabeldata.bg_color[2] = 0x32 / 255.0f;
config.jumplabeldata.bg_color[3] = 1.0f;
config.jumplabeldata.focus_fg_color[0] = 0xed / 255.0f;
config.jumplabeldata.focus_fg_color[1] = 0xa6 / 255.0f;
config.jumplabeldata.focus_fg_color[2] = 0xb4 / 255.0f;
config.jumplabeldata.focus_fg_color[3] = 1.0f;
config.jumplabeldata.focus_bg_color[0] = 0x4e / 255.0f;
config.jumplabeldata.focus_bg_color[1] = 0x45 / 255.0f;
config.jumplabeldata.focus_bg_color[2] = 0x3c / 255.0f;
config.jumplabeldata.focus_bg_color[3] = 1.0f;
config.jumplabeldata.border_color[0] = 0x8b / 255.0f;
config.jumplabeldata.border_color[1] = 0xaa / 255.0f;
config.jumplabeldata.border_color[2] = 0x9b / 255.0f;
config.jumplabeldata.border_color[3] = 1.0f;
config.jumplabeldata.border_width = 4;
config.jumplabeldata.corner_radius = 5;
config.jumplabeldata.padding_x = 10;
config.jumplabeldata.padding_y = 10;
config.rootcolor[0] = 0x32 / 255.0f; config.rootcolor[0] = 0x32 / 255.0f;
config.rootcolor[1] = 0x32 / 255.0f; config.rootcolor[1] = 0x32 / 255.0f;
config.rootcolor[2] = 0x32 / 255.0f; config.rootcolor[2] = 0x32 / 255.0f;
@ -3589,6 +3815,8 @@ bool parse_config(void) {
config.tag_rules = NULL; config.tag_rules = NULL;
config.tag_rules_count = 0; config.tag_rules_count = 0;
config.cursor_theme = NULL; config.cursor_theme = NULL;
config.jumplabeldata.font_desc = NULL;
config.tabdata.font_desc = NULL;
config.tablet_map_to_mon = NULL; config.tablet_map_to_mon = NULL;
strcpy(config.keymode, "default"); strcpy(config.keymode, "default");
@ -3726,6 +3954,10 @@ void reapply_property(void) {
c->bw = config.borderpx; c->bw = config.borderpx;
} }
mango_jump_label_node_apply_config(c->jump_label_node,
&config.jumplabeldata);
mango_tab_bar_node_apply_config(c->tab_bar_node, &config.tabdata);
wlr_scene_rect_set_color(c->droparea, config.dropcolor); wlr_scene_rect_set_color(c->droparea, config.dropcolor);
wlr_scene_rect_set_color(c->splitindicator[0], config.splitcolor); wlr_scene_rect_set_color(c->splitindicator[0], config.splitcolor);
wlr_scene_rect_set_color(c->splitindicator[1], config.splitcolor); wlr_scene_rect_set_color(c->splitindicator[1], config.splitcolor);

View file

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

View file

@ -137,6 +137,7 @@ int32_t focusdir(const Arg *arg) {
Client *c = NULL; Client *c = NULL;
c = direction_select(arg); c = direction_select(arg);
if (!selmon->isoverview) if (!selmon->isoverview)
c = get_focused_stack_client(c, arg->tc); c = get_focused_stack_client(c, arg->tc);
if (c) { if (c) {
@ -265,7 +266,7 @@ int32_t incnmaster(const Arg *arg) {
if (!arg || !selmon) if (!arg || !selmon)
return 0; return 0;
selmon->pertag->nmasters[selmon->pertag->curtag] = selmon->pertag->nmasters[selmon->pertag->curtag] =
MAX(selmon->pertag->nmasters[selmon->pertag->curtag] + arg->i, 0); MANGO_MAX(selmon->pertag->nmasters[selmon->pertag->curtag] + arg->i, 0);
arrange(selmon, false, false); arrange(selmon, false, false);
return 0; return 0;
} }
@ -737,12 +738,12 @@ int32_t smartmovewin(const Arg *arg) {
continue; continue;
buttom = tc->geom.y + tc->geom.height + config.gappiv; buttom = tc->geom.y + tc->geom.height + config.gappiv;
if (top > buttom && ny < buttom) { if (top > buttom && ny < buttom) {
tar = MAX(tar, buttom); tar = MANGO_MAX(tar, buttom);
}; };
} }
ny = tar == -99999 ? ny : tar; ny = tar == -99999 ? ny : tar;
ny = MAX(ny, c->mon->w.y + c->mon->gappov); ny = MANGO_MAX(ny, c->mon->w.y + c->mon->gappov);
break; break;
case DOWN: case DOWN:
tar = 99999; tar = 99999;
@ -757,12 +758,12 @@ int32_t smartmovewin(const Arg *arg) {
continue; continue;
top = tc->geom.y - config.gappiv; top = tc->geom.y - config.gappiv;
if (buttom < top && (ny + c->geom.height) > top) { if (buttom < top && (ny + c->geom.height) > top) {
tar = MIN(tar, top - c->geom.height); tar = MANGO_MIN(tar, top - c->geom.height);
}; };
} }
ny = tar == 99999 ? ny : tar; ny = tar == 99999 ? ny : tar;
ny = MIN(ny, c->mon->w.y + c->mon->w.height - c->geom.height - ny = MANGO_MIN(ny, c->mon->w.y + c->mon->w.height - c->geom.height -
c->mon->gappov); c->mon->gappov);
break; break;
case LEFT: case LEFT:
tar = -99999; tar = -99999;
@ -777,12 +778,12 @@ int32_t smartmovewin(const Arg *arg) {
continue; continue;
right = tc->geom.x + tc->geom.width + config.gappih; right = tc->geom.x + tc->geom.width + config.gappih;
if (left > right && nx < right) { if (left > right && nx < right) {
tar = MAX(tar, right); tar = MANGO_MAX(tar, right);
}; };
} }
nx = tar == -99999 ? nx : tar; nx = tar == -99999 ? nx : tar;
nx = MAX(nx, c->mon->w.x + c->mon->gappoh); nx = MANGO_MAX(nx, c->mon->w.x + c->mon->gappoh);
break; break;
case RIGHT: case RIGHT:
tar = 99999; tar = 99999;
@ -796,12 +797,12 @@ int32_t smartmovewin(const Arg *arg) {
continue; continue;
left = tc->geom.x - config.gappih; left = tc->geom.x - config.gappih;
if (right < left && (nx + c->geom.width) > left) { if (right < left && (nx + c->geom.width) > left) {
tar = MIN(tar, left - c->geom.width); tar = MANGO_MIN(tar, left - c->geom.width);
}; };
} }
nx = tar == 99999 ? nx : tar; nx = tar == 99999 ? nx : tar;
nx = MIN(nx, c->mon->w.x + c->mon->w.width - c->geom.width - nx = MANGO_MIN(nx, c->mon->w.x + c->mon->w.width - c->geom.width -
c->mon->gappoh); c->mon->gappoh);
break; break;
} }
@ -829,7 +830,7 @@ int32_t smartresizewin(const Arg *arg) {
switch (arg->i) { switch (arg->i) {
case UP: case UP:
nh -= selmon->w.height / 8; nh -= selmon->w.height / 8;
nh = MAX(nh, selmon->w.height / 10); nh = MANGO_MAX(nh, selmon->w.height / 10);
break; break;
case DOWN: case DOWN:
tar = -99999; tar = -99999;
@ -844,7 +845,7 @@ int32_t smartresizewin(const Arg *arg) {
continue; continue;
top = tc->geom.y - config.gappiv; top = tc->geom.y - config.gappiv;
if (buttom < top && (nh + c->geom.y) > top) { if (buttom < top && (nh + c->geom.y) > top) {
tar = MAX(tar, top - c->geom.y); tar = MANGO_MAX(tar, top - c->geom.y);
}; };
} }
nh = tar == -99999 ? nh : tar; nh = tar == -99999 ? nh : tar;
@ -853,7 +854,7 @@ int32_t smartresizewin(const Arg *arg) {
break; break;
case LEFT: case LEFT:
nw -= selmon->w.width / 16; nw -= selmon->w.width / 16;
nw = MAX(nw, selmon->w.width / 10); nw = MANGO_MAX(nw, selmon->w.width / 10);
break; break;
case RIGHT: case RIGHT:
tar = 99999; tar = 99999;
@ -867,7 +868,7 @@ int32_t smartresizewin(const Arg *arg) {
continue; continue;
left = tc->geom.x - config.gappih; left = tc->geom.x - config.gappih;
if (right < left && (nw + c->geom.x) > left) { if (right < left && (nw + c->geom.x) > left) {
tar = MIN(tar, left - c->geom.x); tar = MANGO_MIN(tar, left - c->geom.x);
}; };
} }
@ -1064,7 +1065,7 @@ int32_t switch_layout(const Arg *arg) {
if (config.circle_layout_count != 0) { if (config.circle_layout_count != 0) {
for (jk = 0; jk < config.circle_layout_count; jk++) { for (jk = 0; jk < config.circle_layout_count; jk++) {
len = MAX( len = MANGO_MAX(
strlen(config.circle_layout[jk]), strlen(config.circle_layout[jk]),
strlen(selmon->pertag->ltidxs[selmon->pertag->curtag]->name)); strlen(selmon->pertag->ltidxs[selmon->pertag->curtag]->name));
@ -1083,7 +1084,8 @@ int32_t switch_layout(const Arg *arg) {
} }
for (ji = 0; ji < LENGTH(layouts); ji++) { for (ji = 0; ji < LENGTH(layouts); ji++) {
len = MAX(strlen(layouts[ji].name), strlen(target_layout_name)); len =
MANGO_MAX(strlen(layouts[ji].name), strlen(target_layout_name));
if (strncmp(layouts[ji].name, target_layout_name, len) == 0) { if (strncmp(layouts[ji].name, target_layout_name, len) == 0) {
selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[ji]; selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[ji];
@ -1738,6 +1740,10 @@ int32_t toggleoverview(const Arg *arg) {
uint32_t target; uint32_t target;
uint32_t visible_client_number = 0; uint32_t visible_client_number = 0;
if (!selmon->isoverview && selmon->is_jump_mode) {
finish_jump_mode(selmon);
}
if (selmon->isoverview) { if (selmon->isoverview) {
wl_list_for_each(c, &clients, link) if (c && c->mon == selmon && wl_list_for_each(c, &clients, link) if (c && c->mon == selmon &&
!client_is_unmanaged(c) && !client_is_unmanaged(c) &&
@ -1782,6 +1788,7 @@ int32_t toggleoverview(const Arg *arg) {
} }
} }
} else { } else {
selmon->tagset[selmon->seltags] = target; selmon->tagset[selmon->seltags] = target;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c && c->mon == selmon && !c->iskilling && if (c && c->mon == selmon && !c->iskilling &&
@ -1795,6 +1802,24 @@ int32_t toggleoverview(const Arg *arg) {
view(&(Arg){.ui = target}, false); view(&(Arg){.ui = target}, false);
fix_mon_tagset_from_overview(selmon); fix_mon_tagset_from_overview(selmon);
refresh_monitors_workspaces_status(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; return 0;
} }

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

@ -0,0 +1,845 @@
#include "text-node.h"
#include <cairo.h>
#include <drm_fourcc.h>
#include <glib.h>
#include <pango/pangocairo.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/interfaces/wlr_buffer.h>
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;
}
}
static void text_buffer_destroy(struct wlr_buffer *wlr_buffer) {
struct mango_text_buffer *buf = wl_container_of(wlr_buffer, buf, base);
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_jump_label_node *
mango_jump_label_node_create(struct wlr_scene_tree *parent,
DecorateDrawData data) {
struct mango_jump_label_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;
}
memcpy(node->fg_color, data.fg_color, sizeof(node->fg_color));
memcpy(node->bg_color, data.bg_color, sizeof(node->bg_color));
memcpy(node->focus_fg_color, data.focus_fg_color,
sizeof(node->focus_fg_color));
memcpy(node->focus_bg_color, data.focus_bg_color,
sizeof(node->focus_bg_color));
memcpy(node->border_color, data.border_color, sizeof(node->border_color));
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 =
g_strdup(data.font_desc ? data.font_desc : "monospace Bold 16");
node->cached_text = NULL;
node->cached_scale = -1.0f;
node->cached_font_desc = NULL;
node->focused = false;
node->cached_focused = false;
node->measure_surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
node->measure_cr = cairo_create(node->measure_surface);
node->measure_context = pango_cairo_create_context(node->measure_cr);
node->measure_layout = pango_layout_new(node->measure_context);
node->measure_scale = 1.0f;
node->scene_buffer->node.data = NULL;
return node;
}
void mango_jump_label_node_destroy(struct mango_jump_label_node *node) {
if (!node)
return;
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
if (node->surface) {
cairo_surface_destroy(node->surface);
node->surface = NULL;
}
if (node->measure_layout)
g_object_unref(node->measure_layout);
if (node->measure_context)
g_object_unref(node->measure_context);
if (node->measure_cr)
cairo_destroy(node->measure_cr);
if (node->measure_surface)
cairo_surface_destroy(node->measure_surface);
wlr_scene_node_destroy(&node->scene_buffer->node);
g_free(node->font_desc);
g_free(node->cached_text);
g_free(node->cached_font_desc);
free(node);
}
void mango_jump_label_node_set_background(struct mango_jump_label_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_jump_label_node_set_border(struct mango_jump_label_node *node,
float r, float g, float b, float a,
int32_t width, int32_t 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 ? width : 0;
node->corner_radius = radius;
}
void mango_jump_label_node_set_padding(struct mango_jump_label_node *node,
int32_t pad_x, int32_t pad_y) {
if (!node)
return;
node->padding_x = pad_x >= 0 ? pad_x : 0;
node->padding_y = pad_y >= 0 ? pad_y : 0;
}
static void get_text_pixel_size(struct mango_jump_label_node *node,
const char *text, float scale, int32_t *out_w,
int32_t *out_h) {
if (node->measure_scale != scale) {
pango_cairo_context_set_resolution(node->measure_context, 96.0 * scale);
node->measure_scale = scale;
}
PangoFontDescription *desc = get_cached_font_desc(node->font_desc);
pango_layout_set_font_description(node->measure_layout, desc);
pango_layout_set_text(node->measure_layout, text, -1);
pango_layout_get_pixel_size(node->measure_layout, out_w, out_h);
}
static void draw_rounded_rect(cairo_t *cr, double x, double y, double w,
double h, double r) {
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_jump_label_node_update(struct mango_jump_label_node *node,
const char *text, float scale) {
if (!node || !text)
return;
if (scale <= 0.0f)
scale = 1.0f;
/* 脏检查,加入 focused 状态 */
if (node->cached_scale == scale && node->cached_font_desc &&
strcmp(node->cached_font_desc, node->font_desc) == 0 &&
node->cached_text && strcmp(node->cached_text, text) == 0 &&
memcmp(node->cached_fg_color, node->fg_color, sizeof(node->fg_color)) ==
0 &&
memcmp(node->cached_bg_color, node->bg_color, sizeof(node->bg_color)) ==
0 &&
memcmp(node->cached_focus_fg_color, node->focus_fg_color,
sizeof(node->focus_fg_color)) == 0 &&
memcmp(node->cached_focus_bg_color, node->focus_bg_color,
sizeof(node->focus_bg_color)) == 0 &&
memcmp(node->cached_border_color, node->border_color,
sizeof(node->border_color)) == 0 &&
node->cached_border_width == node->border_width &&
node->cached_corner_radius == node->corner_radius &&
node->cached_padding_x == node->padding_x &&
node->cached_padding_y == node->padding_y &&
node->cached_focused == node->focused) {
return;
}
/* 更新缓存 */
g_free(node->cached_text);
node->cached_text = g_strdup(text);
g_free(node->cached_font_desc);
node->cached_font_desc = g_strdup(node->font_desc);
node->cached_scale = scale;
memcpy(node->cached_fg_color, node->fg_color, sizeof(node->fg_color));
memcpy(node->cached_bg_color, node->bg_color, sizeof(node->bg_color));
memcpy(node->cached_focus_fg_color, node->focus_fg_color,
sizeof(node->focus_fg_color));
memcpy(node->cached_focus_bg_color, node->focus_bg_color,
sizeof(node->focus_bg_color));
memcpy(node->cached_border_color, node->border_color,
sizeof(node->border_color));
node->cached_border_width = node->border_width;
node->cached_corner_radius = node->corner_radius;
node->cached_padding_x = node->padding_x;
node->cached_padding_y = node->padding_y;
node->cached_focused = node->focused;
int32_t text_pixel_w, text_pixel_h;
get_text_pixel_size(node, text, scale, &text_pixel_w, &text_pixel_h);
if (text_pixel_w <= 0 || text_pixel_h <= 0) {
wlr_scene_buffer_set_buffer(node->scene_buffer, NULL);
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
if (node->surface) {
cairo_surface_destroy(node->surface);
node->surface = NULL;
}
node->logical_width = 0;
node->logical_height = 0;
wlr_scene_buffer_set_dest_size(node->scene_buffer, 0, 0);
return;
}
int32_t logical_text_w = (int32_t)(text_pixel_w / scale + 0.5f);
int32_t logical_text_h = (int32_t)(text_pixel_h / scale + 0.5f);
int32_t box_logical_w = logical_text_w + 2 * node->padding_x;
int32_t box_logical_h = logical_text_h + 2 * node->padding_y;
int32_t required_pixel_w =
(int32_t)((box_logical_w + 2 * node->border_width) * scale + 0.5f);
int32_t required_pixel_h =
(int32_t)((box_logical_h + 2 * node->border_width) * scale + 0.5f);
if (required_pixel_w < 1)
required_pixel_w = 1;
if (required_pixel_h < 1)
required_pixel_h = 1;
bool surface_size_changed = (!node->surface) ||
(node->surface_pixel_w != required_pixel_w) ||
(node->surface_pixel_h != required_pixel_h);
if (surface_size_changed) {
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
if (node->surface) {
cairo_surface_destroy(node->surface);
node->surface = NULL;
}
node->surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, required_pixel_w, required_pixel_h);
node->surface_pixel_w = required_pixel_w;
node->surface_pixel_h = required_pixel_h;
}
cairo_t *cr = cairo_create(node->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 border = node->border_width * scale;
double bg_x = border;
double bg_y = border;
double bg_w = box_logical_w * scale;
double bg_h = box_logical_h * scale;
double radius;
if (node->corner_radius < 0) {
radius = (bg_w < bg_h ? bg_w : bg_h) / 2.0;
} else {
radius = node->corner_radius * scale;
}
if (radius > bg_w / 2.0)
radius = bg_w / 2.0;
if (radius > bg_h / 2.0)
radius = bg_h / 2.0;
const float *active_bg =
node->focused ? node->focus_bg_color : node->bg_color;
const float *active_fg =
node->focused ? node->focus_fg_color : node->fg_color;
bool draw_bg = (active_bg[3] > 0.0f); // 使用 active_bg
bool draw_border =
(node->border_width > 0) && (node->border_color[3] > 0.0f);
if (draw_bg) {
cairo_set_source_rgba(cr, active_bg[0], active_bg[1], active_bg[2],
active_bg[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);
double text_x = (node->border_width + node->padding_x) * scale;
double text_y = (node->border_width + node->padding_y) * scale;
cairo_translate(cr, text_x, text_y);
PangoContext *ctx = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(ctx, 96.0 * scale);
PangoLayout *layout = pango_layout_new(ctx);
PangoFontDescription *desc = get_cached_font_desc(node->font_desc);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, text, -1);
cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2],
active_fg[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);
double half_lw = border * 0.5;
double bx = bg_x - half_lw;
double by = bg_y - half_lw;
double bw = bg_w + border;
double bh = bg_h + border;
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);
} else {
cairo_rectangle(cr, bx, by, bw, bh);
}
cairo_stroke(cr);
}
cairo_surface_flush(node->surface);
cairo_destroy(cr);
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
struct mango_text_buffer *buf = calloc(1, sizeof(*buf));
if (!buf) {
return;
}
wlr_buffer_init(&buf->base, &text_buffer_impl, node->surface_pixel_w,
node->surface_pixel_h);
buf->surface = node->surface;
node->buffer = buf;
wlr_scene_buffer_set_buffer(node->scene_buffer, &buf->base);
node->logical_width = box_logical_w + 2 * node->border_width;
node->logical_height = box_logical_h + 2 * node->border_width;
wlr_scene_buffer_set_dest_size(node->scene_buffer, node->logical_width,
node->logical_height);
}
void mango_jump_label_node_set_focus(struct mango_jump_label_node *node,
bool focused) {
if (!node || node->focused == focused)
return;
node->focused = focused;
// 使用缓存的文本和缩放触发重绘(如果无文本则不重绘)
if (node->cached_text && node->cached_scale > 0.0f) {
mango_jump_label_node_update(node, node->cached_text,
node->cached_scale);
}
}
struct mango_tab_bar_node *
mango_tab_bar_node_create(void *mango_node_data, struct wlr_scene_tree *parent,
DecorateDrawData data, int32_t width,
int32_t height) {
struct mango_tab_bar_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;
}
memcpy(node->fg_color, data.fg_color, sizeof(node->fg_color));
memcpy(node->bg_color, data.bg_color, sizeof(node->bg_color));
memcpy(node->focus_fg_color, data.focus_fg_color,
sizeof(node->focus_fg_color));
memcpy(node->focus_bg_color, data.focus_bg_color,
sizeof(node->focus_bg_color));
memcpy(node->border_color, data.border_color, sizeof(node->border_color));
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 =
g_strdup(data.font_desc ? data.font_desc : "monospace Bold 16");
node->target_width = width;
node->target_height = height;
node->focused = false;
node->cached_focused = false;
node->measure_surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
node->measure_cr = cairo_create(node->measure_surface);
node->measure_context = pango_cairo_create_context(node->measure_cr);
node->measure_layout = pango_layout_new(node->measure_context);
node->measure_scale = 1.0f;
node->cached_scale = -1.0f;
node->last_text = NULL;
node->last_scale = 0.0f;
node->scene_buffer->node.data = mango_node_data;
return node;
}
void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node) {
if (!node)
return;
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
if (node->surface) {
cairo_surface_destroy(node->surface);
node->surface = NULL;
}
if (node->measure_surface) {
cairo_surface_destroy(node->measure_surface);
node->measure_surface = NULL;
}
if (node->measure_layout)
g_object_unref(node->measure_layout);
if (node->measure_context)
g_object_unref(node->measure_context);
if (node->measure_cr)
cairo_destroy(node->measure_cr);
void *data = node->scene_buffer->node.data;
wlr_scene_node_destroy(&node->scene_buffer->node);
g_free(node->font_desc);
g_free(node->cached_text);
g_free(node->cached_font_desc);
g_free(node->last_text);
free(data);
free(node);
}
void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width,
int32_t height) {
if (!node)
return;
if (width < 0)
width = 0;
if (height < 0)
height = 0;
if (node->target_width == width && node->target_height == height)
return;
node->target_width = width;
node->target_height = height;
const char *redraw_text = node->last_text ? node->last_text : "";
float redraw_scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, redraw_text, redraw_scale);
}
void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
const char *text, float scale) {
if (!node || !text)
return;
if (scale <= 0.0f)
scale = 1.0f;
char *safe_text = g_strdup(text);
g_free(node->last_text);
node->last_text = safe_text; // 所有权转移
node->last_scale = scale;
// 脏检查加入 focused
if (node->cached_scale == scale && node->cached_font_desc &&
strcmp(node->cached_font_desc, node->font_desc) == 0 &&
node->cached_text && strcmp(node->cached_text, safe_text) == 0 &&
memcmp(node->cached_fg_color, node->fg_color, sizeof(node->fg_color)) ==
0 &&
memcmp(node->cached_bg_color, node->bg_color, sizeof(node->bg_color)) ==
0 &&
memcmp(node->cached_focus_fg_color, node->focus_fg_color,
sizeof(node->focus_fg_color)) == 0 &&
memcmp(node->cached_focus_bg_color, node->focus_bg_color,
sizeof(node->focus_bg_color)) == 0 &&
memcmp(node->cached_border_color, node->border_color,
sizeof(node->border_color)) == 0 &&
node->cached_border_width == node->border_width &&
node->cached_corner_radius == node->corner_radius &&
node->cached_padding_x == node->padding_x &&
node->cached_padding_y == node->padding_y &&
node->cached_target_width == node->target_width &&
node->cached_target_height == node->target_height &&
node->cached_focused == node->focused) {
return;
}
// 更新缓存
g_free(node->cached_text);
node->cached_text = g_strdup(safe_text);
g_free(node->cached_font_desc);
node->cached_font_desc = g_strdup(node->font_desc);
node->cached_scale = scale;
memcpy(node->cached_fg_color, node->fg_color, sizeof(node->fg_color));
memcpy(node->cached_bg_color, node->bg_color, sizeof(node->bg_color));
memcpy(node->cached_focus_fg_color, node->focus_fg_color,
sizeof(node->focus_fg_color));
memcpy(node->cached_focus_bg_color, node->focus_bg_color,
sizeof(node->focus_bg_color));
memcpy(node->cached_border_color, node->border_color,
sizeof(node->border_color));
node->cached_border_width = node->border_width;
node->cached_corner_radius = node->corner_radius;
node->cached_padding_x = node->padding_x;
node->cached_padding_y = node->padding_y;
node->cached_target_width = node->target_width;
node->cached_target_height = node->target_height;
node->cached_focused = node->focused;
if (node->target_width <= 0 || node->target_height <= 0) {
wlr_scene_buffer_set_buffer(node->scene_buffer, NULL);
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
if (node->surface) {
cairo_surface_destroy(node->surface);
node->surface = NULL;
}
node->logical_width = 0;
node->logical_height = 0;
wlr_scene_buffer_set_dest_size(node->scene_buffer, 0, 0);
return;
}
int32_t box_logical_w = node->target_width - 2 * node->border_width;
int32_t box_logical_h = node->target_height - 2 * node->border_width;
if (box_logical_w < 0)
box_logical_w = 0;
if (box_logical_h < 0)
box_logical_h = 0;
int32_t required_pixel_w = (int32_t)(node->target_width * scale + 0.5f);
int32_t required_pixel_h = (int32_t)(node->target_height * scale + 0.5f);
if (required_pixel_w < 1)
required_pixel_w = 1;
if (required_pixel_h < 1)
required_pixel_h = 1;
bool surface_size_changed = (!node->surface) ||
(node->surface_pixel_w != required_pixel_w) ||
(node->surface_pixel_h != required_pixel_h);
if (surface_size_changed) {
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
if (node->surface) {
cairo_surface_destroy(node->surface);
node->surface = NULL;
}
node->surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, required_pixel_w, required_pixel_h);
node->surface_pixel_w = required_pixel_w;
node->surface_pixel_h = required_pixel_h;
}
cairo_t *cr = cairo_create(node->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 border_phys = node->border_width * scale;
double bg_x = border_phys;
double bg_y = border_phys;
double bg_w = box_logical_w * scale;
double bg_h = box_logical_h * scale;
double radius;
if (node->corner_radius < 0) {
radius = (bg_w < bg_h ? bg_w : bg_h) / 2.0;
} else {
radius = node->corner_radius * scale;
}
if (radius > bg_w / 2.0)
radius = bg_w / 2.0;
if (radius > bg_h / 2.0)
radius = bg_h / 2.0;
const float *active_bg =
node->focused ? node->focus_bg_color : node->bg_color;
const float *active_fg =
node->focused ? node->focus_fg_color : node->fg_color;
bool draw_bg = (active_bg[3] > 0.0f);
bool draw_border =
(node->border_width > 0) && (node->border_color[3] > 0.0f);
if (draw_bg) {
cairo_set_source_rgba(cr, active_bg[0], active_bg[1], active_bg[2],
active_bg[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);
}
}
int32_t text_area_logical_w = box_logical_w - 2 * node->padding_x;
int32_t text_area_logical_h = box_logical_h - 2 * node->padding_y;
if (text_area_logical_w > 0 && text_area_logical_h > 0) {
cairo_save(cr);
double text_x = (node->border_width + node->padding_x) * scale;
double text_y = (node->border_width + node->padding_y) * scale;
double text_area_w = text_area_logical_w * scale;
double text_area_h = text_area_logical_h * scale;
PangoContext *ctx = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(ctx, 96.0 * scale);
PangoLayout *layout = pango_layout_new(ctx);
PangoFontDescription *desc = get_cached_font_desc(node->font_desc);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, safe_text, -1);
pango_layout_set_wrap(layout, PANGO_WRAP_NONE);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_width(layout, (int)(text_area_w * PANGO_SCALE));
int text_pixel_w, text_pixel_h;
pango_layout_get_pixel_size(layout, &text_pixel_w, &text_pixel_h);
double y_offset = (text_area_h - text_pixel_h) / 2.0;
if (y_offset < 0)
y_offset = 0;
cairo_translate(cr, text_x, text_y + y_offset);
cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2],
active_fg[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_phys);
double half_lw = border_phys * 0.5;
double bx = bg_x - half_lw;
double by = bg_y - half_lw;
double bw = bg_w + border_phys;
double bh = bg_h + border_phys;
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);
} else {
cairo_rectangle(cr, bx, by, bw, bh);
}
cairo_stroke(cr);
}
cairo_surface_flush(node->surface);
cairo_destroy(cr);
if (node->buffer) {
wlr_buffer_drop(&node->buffer->base);
node->buffer = NULL;
}
struct mango_text_buffer *buf = calloc(1, sizeof(*buf));
if (!buf)
return;
wlr_buffer_init(&buf->base, &text_buffer_impl, node->surface_pixel_w,
node->surface_pixel_h);
buf->surface = node->surface;
node->buffer = buf;
wlr_scene_buffer_set_buffer(node->scene_buffer, &buf->base);
node->logical_width = node->target_width;
node->logical_height = node->target_height;
wlr_scene_buffer_set_dest_size(node->scene_buffer, node->logical_width,
node->logical_height);
}
void mango_tab_bar_node_set_focus(struct mango_tab_bar_node *node,
bool focused) {
if (!node || node->focused == focused)
return;
node->focused = focused;
if (node->last_text) {
float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, node->last_text, scale);
}
}
void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node,
const float fg[4], const float bg[4]) {
if (!node)
return;
memcpy(node->fg_color, fg, sizeof(node->fg_color));
memcpy(node->bg_color, bg, sizeof(node->bg_color));
if (!node->focused && node->last_text) {
float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, node->last_text, scale);
}
}
void mango_jump_label_node_apply_config(struct mango_jump_label_node *node,
const DecorateDrawData *data) {
if (!node || !data)
return;
memcpy(node->fg_color, data->fg_color, sizeof(node->fg_color));
memcpy(node->bg_color, data->bg_color, sizeof(node->bg_color));
memcpy(node->focus_fg_color, data->focus_fg_color,
sizeof(node->focus_fg_color));
memcpy(node->focus_bg_color, data->focus_bg_color,
sizeof(node->focus_bg_color));
memcpy(node->border_color, data->border_color, sizeof(node->border_color));
node->border_width = data->border_width;
node->corner_radius = data->corner_radius;
node->padding_x = data->padding_x;
node->padding_y = data->padding_y;
g_free(node->font_desc);
node->font_desc =
g_strdup(data->font_desc ? data->font_desc : "monospace Bold 16");
if (node->cached_text && node->cached_scale > 0.0f) {
mango_jump_label_node_update(node, node->cached_text,
node->cached_scale);
}
}
void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node,
const DecorateDrawData *data) {
if (!node || !data)
return;
memcpy(node->fg_color, data->fg_color, sizeof(node->fg_color));
memcpy(node->bg_color, data->bg_color, sizeof(node->bg_color));
memcpy(node->focus_fg_color, data->focus_fg_color,
sizeof(node->focus_fg_color));
memcpy(node->focus_bg_color, data->focus_bg_color,
sizeof(node->focus_bg_color));
memcpy(node->border_color, data->border_color, sizeof(node->border_color));
node->border_width = data->border_width;
node->corner_radius = data->corner_radius;
node->padding_x = data->padding_x;
node->padding_y = data->padding_y;
g_free(node->font_desc);
node->font_desc =
g_strdup(data->font_desc ? data->font_desc : "monospace Bold 16");
if (node->last_text) {
float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, node->last_text, scale);
}
}

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

@ -0,0 +1,166 @@
#ifndef jump_label_node_H
#define jump_label_node_H
#include <cairo.h>
#include <pango/pango.h>
#include <pango/pangocairo.h>
#include <stdbool.h>
#include <stdint.h>
#include <wlr/types/wlr_scene.h>
// 原有结构体,假设已存在
typedef struct {
float fg_color[4];
float bg_color[4];
float focus_fg_color[4];
float focus_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;
} DecorateDrawData;
struct mango_text_buffer {
struct wlr_buffer base;
cairo_surface_t *surface;
};
struct mango_jump_label_node {
struct wlr_scene_buffer *scene_buffer;
struct mango_text_buffer *buffer;
cairo_surface_t *surface;
int surface_pixel_w, surface_pixel_h;
float fg_color[4];
float bg_color[4];
float focus_fg_color[4];
float focus_bg_color[4];
float border_color[4];
int32_t border_width;
int32_t corner_radius;
int32_t padding_x;
int32_t padding_y;
char *font_desc;
// 缓存
char *cached_text;
char *cached_font_desc;
float cached_scale;
float cached_fg_color[4];
float cached_bg_color[4];
float cached_focus_fg_color[4];
float cached_focus_bg_color[4];
float cached_border_color[4];
int32_t cached_border_width;
int32_t cached_corner_radius;
int32_t cached_padding_x;
int32_t cached_padding_y;
bool cached_focused;
bool focused;
// 测量
cairo_surface_t *measure_surface;
cairo_t *measure_cr;
PangoContext *measure_context;
PangoLayout *measure_layout;
float measure_scale;
int32_t logical_width;
int32_t logical_height;
};
struct mango_tab_bar_node {
struct wlr_scene_buffer *scene_buffer;
struct mango_text_buffer *buffer;
cairo_surface_t *surface;
int surface_pixel_w, surface_pixel_h;
// 初始配置
float fg_color[4];
float bg_color[4];
float focus_fg_color[4];
float focus_bg_color[4];
float border_color[4];
int32_t border_width;
int32_t corner_radius;
int32_t padding_x;
int32_t padding_y;
char *font_desc;
// 尺寸
int32_t target_width;
int32_t target_height;
// 缓存
char *cached_text;
char *cached_font_desc;
float cached_scale;
float cached_fg_color[4];
float cached_bg_color[4];
float cached_focus_fg_color[4];
float cached_focus_bg_color[4];
float cached_border_color[4];
int32_t cached_border_width;
int32_t cached_corner_radius;
int32_t cached_padding_x;
int32_t cached_padding_y;
int32_t cached_target_width;
int32_t cached_target_height;
bool cached_focused;
bool focused;
// 上次绘制参数(用于尺寸变化重绘)
char *last_text;
float last_scale;
// 测量
cairo_surface_t *measure_surface;
cairo_t *measure_cr;
PangoContext *measure_context;
PangoLayout *measure_layout;
float measure_scale;
int32_t logical_width;
int32_t logical_height;
};
void mango_text_global_finish(void);
struct mango_jump_label_node *
mango_jump_label_node_create(struct wlr_scene_tree *parent,
DecorateDrawData data);
void mango_jump_label_node_destroy(struct mango_jump_label_node *node);
void mango_jump_label_node_set_background(struct mango_jump_label_node *node,
float r, float g, float b, float a);
void mango_jump_label_node_set_border(struct mango_jump_label_node *node,
float r, float g, float b, float a,
int32_t width, int32_t radius);
void mango_jump_label_node_set_padding(struct mango_jump_label_node *node,
int32_t pad_x, int32_t pad_y);
void mango_jump_label_node_update(struct mango_jump_label_node *node,
const char *text, float scale);
struct mango_tab_bar_node *
mango_tab_bar_node_create(void *mango_node_data, struct wlr_scene_tree *parent,
DecorateDrawData data, int32_t width, int32_t height);
void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node);
void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width,
int32_t height);
void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
const char *text, float scale);
void mango_jump_label_node_set_focus(struct mango_jump_label_node *node,
bool focused);
void mango_tab_bar_node_set_focus(struct mango_tab_bar_node *node,
bool focused);
void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node,
const float fg[4], const float bg[4]);
void mango_jump_label_node_apply_config(struct mango_jump_label_node *node,
const DecorateDrawData *data);
void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node,
const DecorateDrawData *data);
#endif // jump_label_node_H

View file

@ -188,8 +188,12 @@ Client *find_client_by_direction(Client *tc, const Arg *arg,
continue; continue;
if (!findfloating && c->isfloating) if (!findfloating && c->isfloating)
continue; continue;
if (c->is_monocle_hide)
continue;
if (c->isunglobal) if (c->isunglobal)
continue; continue;
if (c->is_monocle_hide)
continue;
if (!config.focus_cross_monitor && c->mon != tc->mon) if (!config.focus_cross_monitor && c->mon != tc->mon)
continue; continue;
if (!(c->tags & c->mon->tagset[c->mon->seltags])) if (!(c->tags & c->mon->tagset[c->mon->seltags]))
@ -440,7 +444,7 @@ Client *get_focused_stack_client(Client *sc, Client *custom_focus_client) {
return sc; return sc;
wl_list_for_each(tc, &fstack, flink) { wl_list_for_each(tc, &fstack, flink) {
if (tc->iskilling || tc->isunglobal) if (tc->iskilling || tc->isunglobal || tc->is_monocle_hide)
continue; continue;
if (!VISIBLEON(tc, sc->mon)) if (!VISIBLEON(tc, sc->mon))
continue; continue;

View file

@ -26,6 +26,14 @@ bool is_scroller_layout(Monitor *m) {
return false; return false;
} }
bool is_monocle_layout(Monitor *m) {
if (m->pertag->ltidxs[m->pertag->curtag]->id == MONOCLE)
return true;
return false;
}
bool is_centertile_layout(Monitor *m) { bool is_centertile_layout(Monitor *m) {
if (m->pertag->ltidxs[m->pertag->curtag]->id == CENTER_TILE) if (m->pertag->ltidxs[m->pertag->curtag]->id == CENTER_TILE)

View file

@ -37,6 +37,21 @@ void set_size_per(Monitor *m, Client *c) {
} }
} }
void monocle_set_focus(Client *c, bool focused) {
if (!c || !c->mon)
return;
c->is_monocle_hide = !focused;
mango_tab_bar_node_set_focus(c->tab_bar_node, focused);
wlr_scene_node_set_enabled(&c->scene->node, focused);
if (!focused) {
c->animation.current = c->animainit_geom = c->animation.initial =
c->pending = c->current = c->geom;
}
}
void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, int32_t offsety, uint32_t time,
int32_t type) { int32_t type) {
@ -1128,6 +1143,20 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
set_size_per(m, c); set_size_per(m, c);
} }
if (m->is_jump_mode && !c->jump_label_node) {
client_add_jump_label_node(c);
}
if (m->pertag->ltidxs[m->pertag->curtag]->id == MONOCLE &&
!c->tab_bar_node) {
client_add_tab_bar_node(c);
}
if (c->tab_bar_node && c->mon == m) {
wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node,
false);
}
if (c->mon == m && (c->isglobal || c->isunglobal)) { if (c->mon == m && (c->isglobal || c->isunglobal)) {
c->tags = m->tagset[m->seltags]; c->tags = m->tagset[m->seltags];
} }

View file

@ -259,7 +259,8 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
if (node->client) { if (node->client) {
if (!node->client->isfullscreen && if (!node->client->isfullscreen &&
!node->client->ismaximizescreen) { !node->client->ismaximizescreen) {
struct wlr_box box = {ax, ay, MAX(1, aw), MAX(1, ah)}; struct wlr_box box = {ax, ay, MANGO_MAX(1, aw),
MANGO_MAX(1, ah)};
resize(node->client, box, 0); resize(node->client, box, 0);
} }
} }
@ -273,12 +274,12 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
node->container_w = aw; node->container_w = aw;
node->container_h = ah; node->container_h = ah;
if (node->split_h) { if (node->split_h) {
int32_t w1 = MAX(1, (int32_t)(aw * node->ratio) - gap_h / 2); int32_t w1 = MANGO_MAX(1, (int32_t)(aw * node->ratio) - gap_h / 2);
dwindle_assign(node->first, ax, ay, w1, ah, gap_h, gap_v); dwindle_assign(node->first, ax, ay, w1, ah, gap_h, gap_v);
dwindle_assign(node->second, ax + w1 + gap_h, ay, aw - w1 - gap_h, ah, dwindle_assign(node->second, ax + w1 + gap_h, ay, aw - w1 - gap_h, ah,
gap_h, gap_v); gap_h, gap_v);
} else { } else {
int32_t h1 = MAX(1, (int32_t)(ah * node->ratio) - gap_v / 2); int32_t h1 = MANGO_MAX(1, (int32_t)(ah * node->ratio) - gap_v / 2);
dwindle_assign(node->first, ax, ay, aw, h1, gap_h, gap_v); dwindle_assign(node->first, ax, ay, aw, h1, gap_h, gap_v);
dwindle_assign(node->second, ax, ay + h1 + gap_v, aw, ah - h1 - gap_v, dwindle_assign(node->second, ax, ay + h1 + gap_v, aw, ah - h1 - gap_v,
gap_h, gap_v); gap_h, gap_v);
@ -357,7 +358,7 @@ static void dwindle_resize_client(Monitor *m, Client *c) {
return; return;
if (dwindle_locked_h_node) { if (dwindle_locked_h_node) {
float cw = (float)MAX(1, dwindle_locked_h_node->container_w); float cw = (float)MANGO_MAX(1, dwindle_locked_h_node->container_w);
float ox = (float)(cursor->x - drag_begin_cursorx); float ox = (float)(cursor->x - drag_begin_cursorx);
if (config.dwindle_smart_resize) { if (config.dwindle_smart_resize) {
/* Move the boundary toward the cursor: invert direction when /* Move the boundary toward the cursor: invert direction when
@ -374,7 +375,7 @@ static void dwindle_resize_client(Monitor *m, Client *c) {
} }
if (dwindle_locked_v_node) { if (dwindle_locked_v_node) {
float ch = (float)MAX(1, dwindle_locked_v_node->container_h); float ch = (float)MANGO_MAX(1, dwindle_locked_v_node->container_h);
float oy = (float)(cursor->y - drag_begin_cursory); float oy = (float)(cursor->y - drag_begin_cursory);
if (config.dwindle_smart_resize) { if (config.dwindle_smart_resize) {
/* Same logic for the vertical split line. */ /* Same logic for the vertical split line. */
@ -427,13 +428,13 @@ static void dwindle_resize_client_step(Monitor *m, Client *c, int32_t dx,
return; return;
if (h_node && dx) { if (h_node && dx) {
float cw = (float)MAX(1, h_node->container_w); float cw = (float)MANGO_MAX(1, h_node->container_w);
float delta = (float)dx / cw; float delta = (float)dx / cw;
h_node->ratio = CLAMP_FLOAT(h_node->ratio + delta, 0.05f, 0.95f); h_node->ratio = CLAMP_FLOAT(h_node->ratio + delta, 0.05f, 0.95f);
} }
if (v_node && dy) { if (v_node && dy) {
float ch = (float)MAX(1, v_node->container_h); float ch = (float)MANGO_MAX(1, v_node->container_h);
float delta = (float)dy / ch; float delta = (float)dy / ch;
v_node->ratio = CLAMP_FLOAT(v_node->ratio + delta, 0.05f, 0.95f); v_node->ratio = CLAMP_FLOAT(v_node->ratio + delta, 0.05f, 0.95f);
} }

View file

@ -62,7 +62,7 @@ void tile(Monitor *m) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c)) if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue; continue;
if (i < m->pertag->nmasters[m->pertag->curtag]) { if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; r = MANGO_MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
if (c->master_inner_per > 0.0f) { if (c->master_inner_per > 0.0f) {
h = master_surplus_height * c->master_inner_per / h = master_surplus_height * c->master_inner_per /
master_surplus_ratio; master_surplus_ratio;
@ -179,7 +179,7 @@ void right_tile(Monitor *m) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c)) if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue; continue;
if (i < m->pertag->nmasters[m->pertag->curtag]) { if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; r = MANGO_MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
if (c->master_inner_per > 0.0f) { if (c->master_inner_per > 0.0f) {
h = master_surplus_height * c->master_inner_per / h = master_surplus_height * c->master_inner_per /
master_surplus_ratio; master_surplus_ratio;
@ -345,7 +345,7 @@ void center_tile(Monitor *m) {
if (i < nmasters) { if (i < nmasters) {
// 主区域窗口 // 主区域窗口
r = MIN(n, nmasters) - i; r = MANGO_MIN(n, nmasters) - i;
if (c->master_inner_per > 0.0f) { if (c->master_inner_per > 0.0f) {
h = master_surplus_height * c->master_inner_per / h = master_surplus_height * c->master_inner_per /
master_surplus_ratio; master_surplus_ratio;
@ -518,8 +518,8 @@ void deck(Monitor *m) {
continue; continue;
if (i < nmasters) { if (i < nmasters) {
c->master_mfact_per = mfact; c->master_mfact_per = mfact;
int32_t h = int32_t h = (m->w.height - 2 * cur_gappov - my) /
(m->w.height - 2 * cur_gappov - my) / (MIN(n, nmasters) - i); (MANGO_MIN(n, nmasters) - i);
client_tile_resize(c, client_tile_resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh, (struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + cur_gappov + my, .y = m->w.y + cur_gappov + my,
@ -545,32 +545,83 @@ void deck(Monitor *m) {
} }
} }
void // 17 void monocle(Monitor *m) {
monocle(Monitor *m) { Client *c = NULL, *fc = NULL;
Client *c = NULL;
struct wlr_box geom; struct wlr_box geom;
int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gapiv = enablegaps ? m->gappiv : 0;
int32_t cur_gapih = enablegaps ? m->gappih : 0;
cur_gappoh = config.smartgaps && m->visible_fake_tiling_clients == 1 if (config.smartgaps && m->visible_fake_tiling_clients == 1) {
? 0 cur_gappov = cur_gappoh = cur_gapiv = cur_gapih = 0;
: cur_gappoh; }
cur_gappov = config.smartgaps && m->visible_fake_tiling_clients == 1
? 0
: cur_gappov;
wl_list_for_each(c, &clients, link) { int n = m->visible_fake_tiling_clients;
if (!VISIBLEON(c, m) || !ISFAKETILED(c)) if (n == 0)
return;
wl_list_for_each(c, &fstack, flink) {
if (c->iskilling || c->isunglobal || !ISFAKETILED(c))
continue; continue;
if (VISIBLEON(c, m)) {
fc = c;
break;
}
}
if (n == 1) {
geom.x = m->w.x + cur_gappoh; geom.x = m->w.x + cur_gappoh;
geom.y = m->w.y + cur_gappov; geom.y = m->w.y + cur_gappov;
geom.width = m->w.width - 2 * cur_gappoh; geom.width = m->w.width - 2 * cur_gappoh;
geom.height = m->w.height - 2 * cur_gappov; geom.height = m->w.height - 2 * cur_gappov;
client_tile_resize(c, geom, 0); client_tile_resize(fc, geom, 0);
monocle_set_focus(fc, true);
return;
}
int tab_bar_height = config.tab_bar_height;
int tab_bar_inner_gap_height =
config.tab_bar_height > 0 ? 2 * cur_gapiv : 0;
int tab_bar_y_offset = config.tab_bar_height > 0 ? cur_gapiv : 0;
int tab_y = m->w.y + cur_gappov;
int main_y = tab_y + tab_bar_height + tab_bar_y_offset;
int main_height = m->w.height - 2 * cur_gappov - tab_bar_inner_gap_height -
tab_bar_height;
int tab_area_width = m->w.width - 2 * cur_gappoh;
int total_gaps = (n - 1) * cur_gapih;
int base_width = (tab_area_width - total_gaps) / n;
int remainder = (tab_area_width - total_gaps) % n;
int tab_x = m->w.x + cur_gappoh;
int idx = 0;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue;
if (c == fc) {
monocle_set_focus(c, true);
} else {
monocle_set_focus(c, false);
}
geom.x = m->w.x + cur_gappoh;
geom.y = main_y;
geom.width = m->w.width - 2 * cur_gappoh;
geom.height = main_height;
client_tile_resize(c, geom, 0);
int tw = base_width + (idx < remainder ? 1 : 0);
global_draw_tab_bar(c, tab_x, tab_y, tw, tab_bar_height);
tab_x += tw + cur_gapih;
idx++;
} }
if ((c = focustop(m)))
wlr_scene_node_raise_to_top(&c->scene->node);
} }
// 网格布局窗口大小和位置计算 // 网格布局窗口大小和位置计算

View file

@ -353,10 +353,66 @@ void overview_resize(Monitor *m) {
free(c_arr); 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) && !c->isunglobal && !client_is_x11_popup(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_jump_label_node_update(c->jump_label_node, label_text, 1.0f);
wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node,
true);
wlr_scene_node_raise_to_top(
&c->jump_label_node->scene_buffer->node);
wlr_scene_node_set_position(
&c->jump_label_node->scene_buffer->node,
c->geom.width / 2 - c->jump_label_node->logical_width / 2,
c->geom.height / 2 - c->jump_label_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->jump_label_node->scene_buffer->node.enabled) {
c->jump_char = '\0';
wlr_scene_node_set_enabled(
&c->jump_label_node->scene_buffer->node, false);
}
}
}
m->is_jump_mode = 0;
}
void overview(Monitor *m) { void overview(Monitor *m) {
if (config.ov_no_resize) { if (config.ov_no_resize) {
overview_scale(m); overview_scale(m);
} else { } else {
overview_resize(m); overview_resize(m);
} }
if (m->is_jump_mode) {
create_jump_hints(m);
}
} }

View file

@ -58,7 +58,7 @@ void vertical_tile(Monitor *m) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c)) if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue; continue;
if (i < m->pertag->nmasters[m->pertag->curtag]) { if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; r = MANGO_MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
if (c->master_inner_per > 0.0f) { if (c->master_inner_per > 0.0f) {
w = master_surplus_width * c->master_inner_per / w = master_surplus_width * c->master_inner_per /
master_surplus_ratio; master_surplus_ratio;
@ -155,8 +155,8 @@ void vertical_deck(Monitor *m) {
continue; continue;
if (i < nmasters) { if (i < nmasters) {
c->master_mfact_per = mfact; c->master_mfact_per = mfact;
int32_t w = int32_t w = (m->w.width - 2 * cur_gappoh - mx) /
(m->w.width - 2 * cur_gappoh - mx) / (MIN(n, nmasters) - i); (MANGO_MIN(n, nmasters) - i);
client_tile_resize(c, client_tile_resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh + mx, (struct wlr_box){.x = m->w.x + cur_gappoh + mx,
.y = m->w.y + cur_gappov, .y = m->w.y + cur_gappov,

View file

@ -94,10 +94,11 @@
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
#endif #endif
#include "common/util.h" #include "common/util.h"
#include "draw/text-node.h"
/* macros */ /* macros */
#define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MANGO_MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B)) #define MANGO_MIN(A, B) ((A) < (B) ? (A) : (B))
#define GEZERO(A) ((A) >= 0 ? (A) : 0) #define GEZERO(A) ((A) >= 0 ? (A) : 0)
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
#define INSIDEMON(A) \ #define INSIDEMON(A) \
@ -165,6 +166,7 @@ enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向
enum { enum {
LyrBg, LyrBg,
LyrBottom, LyrBottom,
LyrDecorate,
LyrTile, LyrTile,
LyrTop, LyrTop,
LyrFadeOut, LyrFadeOut,
@ -173,6 +175,9 @@ enum {
LyrBlock, LyrBlock,
NUM_LAYERS NUM_LAYERS
}; /* scene layers */ }; /* scene layers */
enum mango_node_type { MANGO_TITLE_NODE, MANGO_jump_label_node };
#ifdef XWAYLAND #ifdef XWAYLAND
enum { enum {
NetWMWindowTypeDialog, NetWMWindowTypeDialog,
@ -239,6 +244,11 @@ typedef struct {
Client *tc; Client *tc;
} Arg; } Arg;
typedef struct {
enum mango_node_type type;
void *node_data;
} MangoNodeData;
typedef struct { typedef struct {
uint32_t mod; uint32_t mod;
uint32_t button; uint32_t button;
@ -262,8 +272,8 @@ typedef struct {
struct wl_list link; struct wl_list link;
struct wlr_input_device *wlr_device; struct wlr_input_device *wlr_device;
struct libinput_device *libinput_device; struct libinput_device *libinput_device;
struct wl_listener destroy_listener; // 用于监听设备销毁事件 struct wl_listener destroy_listener;
void *device_data; // 新增:指向设备特定数据(如 Switch void *device_data;
} InputDevice; } InputDevice;
typedef struct { typedef struct {
@ -329,6 +339,8 @@ struct Client {
struct wlr_ext_image_capture_source_v1 *image_capture_source; struct wlr_ext_image_capture_source_v1 *image_capture_source;
struct wlr_scene_tree *overview_scene_surface; struct wlr_scene_tree *overview_scene_surface;
struct mango_jump_label_node *jump_label_node;
struct mango_tab_bar_node *tab_bar_node;
struct wl_list link; struct wl_list link;
struct wl_list flink; struct wl_list flink;
struct wl_list fadeout_link; struct wl_list fadeout_link;
@ -395,6 +407,7 @@ struct Client {
int32_t istagswitching; int32_t istagswitching;
int32_t isnamedscratchpad; int32_t isnamedscratchpad;
int32_t shield_when_capture; int32_t shield_when_capture;
bool is_monocle_hide;
bool is_pending_open_animation; bool is_pending_open_animation;
bool is_restoring_from_ov; bool is_restoring_from_ov;
float scroller_proportion; float scroller_proportion;
@ -434,6 +447,7 @@ struct Client {
int32_t allow_shortcuts_inhibit; int32_t allow_shortcuts_inhibit;
float scroller_proportion_single; float scroller_proportion_single;
bool isfocusing; bool isfocusing;
char jump_char;
bool enable_drop_area_draw; bool enable_drop_area_draw;
int32_t drop_direction; int32_t drop_direction;
struct wlr_box drag_tile_float_backup_geom; struct wlr_box drag_tile_float_backup_geom;
@ -552,6 +566,7 @@ struct Monitor {
uint32_t ovbk_prev_tagset; uint32_t ovbk_prev_tagset;
Client *sel, *prevsel; Client *sel, *prevsel;
int32_t isoverview; int32_t isoverview;
int32_t is_jump_mode;
int32_t is_in_hotarea; int32_t is_in_hotarea;
int32_t asleep; int32_t asleep;
uint32_t visible_clients; uint32_t visible_clients;
@ -847,6 +862,7 @@ static struct wlr_scene_tree *
wlr_scene_tree_snapshot(struct wlr_scene_node *node, wlr_scene_tree_snapshot(struct wlr_scene_node *node,
struct wlr_scene_tree *parent); struct wlr_scene_tree *parent);
static bool is_scroller_layout(Monitor *m); static bool is_scroller_layout(Monitor *m);
static bool is_monocle_layout(Monitor *m);
static bool is_centertile_layout(Monitor *m); static bool is_centertile_layout(Monitor *m);
static void create_output(struct wlr_backend *backend, void *data); static void create_output(struct wlr_backend *backend, void *data);
static void get_layout_abbr(char *abbr, const char *full_name); static void get_layout_abbr(char *abbr, const char *full_name);
@ -911,6 +927,10 @@ Client *scroll_get_stack_tail_client(Client *c);
static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c); static DwindleNode *dwindle_find_leaf(DwindleNode *node, Client *c);
static void overview_backup_surface(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 "data/static_keymap.h"
#include "dispatch/bind_declare.h" #include "dispatch/bind_declare.h"
#include "layout/layout.h" #include "layout/layout.h"
@ -1143,8 +1163,8 @@ void client_change_mon(Client *c, Monitor *m) {
void applybounds(Client *c, struct wlr_box *bbox) { void applybounds(Client *c, struct wlr_box *bbox) {
/* set minimum possible */ /* set minimum possible */
c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); c->geom.width = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.width);
c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); c->geom.height = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.height);
if (c->geom.x >= bbox->x + bbox->width) if (c->geom.x >= bbox->x + bbox->width)
c->geom.x = bbox->x + bbox->width - c->geom.width; c->geom.x = bbox->x + bbox->width - c->geom.width;
@ -1275,6 +1295,10 @@ void swallow(Client *c, Client *w) {
overview_backup_surface(c); overview_backup_surface(c);
} }
if (w->tab_bar_node) {
wlr_scene_node_set_enabled(&w->tab_bar_node->scene_buffer->node, false);
}
/* 全局链表替换 */ /* 全局链表替换 */
wl_list_insert(&w->link, &c->link); wl_list_insert(&w->link, &c->link);
wl_list_insert(&w->flink, &c->flink); wl_list_insert(&w->flink, &c->flink);
@ -1567,7 +1591,7 @@ void set_float_malposition(Client *tc) {
y = tc->geom.y; y = tc->geom.y;
xreverse = 1; xreverse = 1;
yreverse = 1; yreverse = 1;
offset = MIN(tc->mon->w.width / 20, tc->mon->w.height / 20); offset = MANGO_MIN(tc->mon->w.width / 20, tc->mon->w.height / 20);
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->isfloating && c != tc && VISIBLEON(c, tc->mon) && if (c->isfloating && c != tc && VISIBLEON(c, tc->mon) &&
@ -2382,6 +2406,17 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
return true; return true;
} }
// handle click on tile node
struct wlr_scene_node *node = wlr_scene_node_at(
&layers[LyrDecorate]->node, cursor->x, cursor->y, NULL, NULL);
if (node && node->data) {
MangoNodeData *mangonodedata = (MangoNodeData *)node->data;
if (mangonodedata->type == MANGO_TITLE_NODE) {
Client *c = mangonodedata->node_data;
focusclient(c, 1);
}
}
// 当鼠标焦点在layer上的时候不检测虚拟键盘的mod状态 // 当鼠标焦点在layer上的时候不检测虚拟键盘的mod状态
// 避免layer虚拟键盘锁死mod按键状态 // 避免layer虚拟键盘锁死mod按键状态
hard_keyboard = &kb_group->wlr_group->keyboard; hard_keyboard = &kb_group->wlr_group->keyboard;
@ -2581,6 +2616,8 @@ void cleanup(void) {
/* Destroy after the wayland display (when the monitors are already /* Destroy after the wayland display (when the monitors are already
destroyed) to avoid destroying them with an invalid scene output. */ destroyed) to avoid destroying them with an invalid scene output. */
wlr_scene_node_destroy(&scene->tree.node); wlr_scene_node_destroy(&scene->tree.node);
mango_text_global_finish();
} }
void cleanupmon(struct wl_listener *listener, void *data) { void cleanupmon(struct wl_listener *listener, void *data) {
@ -3800,17 +3837,17 @@ void focusclient(Client *c, int32_t lift) {
// decide whether need to re-arrange // decide whether need to re-arrange
if (c && selmon->prevsel &&
(selmon->prevsel->tags & selmon->tagset[selmon->seltags]) &&
(c->tags & selmon->tagset[selmon->seltags]) && !c->isfloating &&
is_scroller_layout(selmon)) {
arrange(selmon, false, false);
}
// change focus link position // change focus link position
wl_list_remove(&c->flink); wl_list_remove(&c->flink);
wl_list_insert(&fstack, &c->flink); wl_list_insert(&fstack, &c->flink);
if (c && selmon->prevsel &&
(selmon->prevsel->tags & selmon->tagset[selmon->seltags]) &&
(c->tags & selmon->tagset[selmon->seltags]) && !c->isfloating &&
(is_scroller_layout(selmon) || is_monocle_layout(selmon))) {
arrange(selmon, false, false);
}
// change border color // change border color
c->isurgent = 0; c->isurgent = 0;
} }
@ -4207,6 +4244,27 @@ void keypress(struct wl_listener *listener, void *data) {
if (handled) if (handled)
return; 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 /* don't pass when popup is focused
* this is better than having popups (like fuzzel or wmenu) closing * this is better than having popups (like fuzzel or wmenu) closing
* while typing in a passed keybind */ * while typing in a passed keybind */
@ -4288,6 +4346,9 @@ void locksession(struct wl_listener *listener, void *data) {
void init_client_properties(Client *c) { void init_client_properties(Client *c) {
c->grid_col_per = 1.0f; c->grid_col_per = 1.0f;
c->grid_row_per = 1.0f; c->grid_row_per = 1.0f;
c->is_monocle_hide = false;
c->jump_label_node = NULL;
c->tab_bar_node = NULL;
c->overview_scene_surface = NULL; c->overview_scene_surface = NULL;
c->drop_direction = UNDIR; c->drop_direction = UNDIR;
c->enable_drop_area_draw = false; c->enable_drop_area_draw = false;
@ -5579,10 +5640,10 @@ void setfullscreen(Client *c, int32_t fullscreen,
} }
void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv) { void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv) {
selmon->gappoh = MAX(oh, 0); selmon->gappoh = MANGO_MAX(oh, 0);
selmon->gappov = MAX(ov, 0); selmon->gappov = MANGO_MAX(ov, 0);
selmon->gappih = MAX(ih, 0); selmon->gappih = MANGO_MAX(ih, 0);
selmon->gappiv = MAX(iv, 0); selmon->gappiv = MANGO_MAX(iv, 0);
arrange(selmon, false, false); arrange(selmon, false, false);
} }
@ -6534,6 +6595,15 @@ void unmapnotify(struct wl_listener *listener, void *data) {
c->stack_proportion = 0.0f; c->stack_proportion = 0.0f;
if (c->jump_label_node) {
mango_jump_label_node_destroy(c->jump_label_node);
c->jump_label_node = NULL;
}
if (c->tab_bar_node) {
mango_tab_bar_node_destroy(c->tab_bar_node);
c->tab_bar_node = NULL;
}
wlr_scene_node_destroy(&c->scene->node); wlr_scene_node_destroy(&c->scene->node);
printstatus(IPC_WATCH_ARRANGGE); printstatus(IPC_WATCH_ARRANGGE);
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);
@ -6681,6 +6751,7 @@ void updatetitle(struct wl_listener *listener, void *data) {
const char *title; const char *title;
title = client_get_title(c); title = client_get_title(c);
mango_tab_bar_node_update(c->tab_bar_node, title, 1.0);
if (title && c->foreign_toplevel) if (title && c->foreign_toplevel)
wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title);
if (title && c->ext_foreign_toplevel) { if (title && c->ext_foreign_toplevel) {