mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-06-19 14:33:16 -04:00
Merge branch 'mangowm:wl-only' into wl-only
This commit is contained in:
commit
5b58df6650
23 changed files with 1676 additions and 100 deletions
|
|
@ -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. |
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
### 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
|
||||
|
||||
Set the size and theme of your mouse cursor.
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
hwdata
|
||||
seatd
|
||||
pcre2
|
||||
pango
|
||||
cjson
|
||||
libxcb
|
||||
pixman
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ endif
|
|||
|
||||
cc = meson.get_compiler('c')
|
||||
libm = cc.find_library('m')
|
||||
libdrm = dependency('libdrm')
|
||||
xcb = dependency('xcb', required : get_option('xwayland'))
|
||||
xlibs = dependency('xcb-icccm', required : get_option('xwayland'))
|
||||
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')
|
||||
pixman_dep = dependency('pixman-1')
|
||||
cjson_dep = dependency('libcjson')
|
||||
pangocairo_dep = dependency('pangocairo')
|
||||
|
||||
# version info
|
||||
git = find_program('git', required : false)
|
||||
|
|
@ -93,9 +95,11 @@ endif
|
|||
executable('mango-wl',
|
||||
'src/mango.c',
|
||||
'src/common/util.c',
|
||||
'src/draw/text-node.c',
|
||||
wayland_sources,
|
||||
dependencies : [
|
||||
libm,
|
||||
libdrm,
|
||||
xcb,
|
||||
xlibs,
|
||||
wayland_server_dep,
|
||||
|
|
@ -106,6 +110,7 @@ executable('mango-wl',
|
|||
pcre2_dep,
|
||||
pixman_dep,
|
||||
cjson_dep,
|
||||
pangocairo_dep,
|
||||
],
|
||||
install : true,
|
||||
c_args : c_args,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
libX11,
|
||||
libinput,
|
||||
libxcb,
|
||||
libdrm,
|
||||
libxkbcommon,
|
||||
pcre2,
|
||||
pango,
|
||||
cjson,
|
||||
pixman,
|
||||
pkg-config,
|
||||
|
|
@ -49,6 +51,7 @@ stdenv.mkDerivation {
|
|||
libxcb
|
||||
libxkbcommon
|
||||
pcre2
|
||||
pango
|
||||
cjson
|
||||
pixman
|
||||
wayland
|
||||
|
|
@ -56,6 +59,7 @@ stdenv.mkDerivation {
|
|||
wlroots_0_19
|
||||
scenefx
|
||||
libGL
|
||||
libdrm
|
||||
]
|
||||
++ lib.optionals enableXWayland [
|
||||
libX11
|
||||
|
|
|
|||
|
|
@ -96,3 +96,27 @@ void client_pending_force_kill(Client *c) {
|
|||
return;
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
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)) {
|
||||
c->is_clip_to_hide = true;
|
||||
wlr_scene_node_set_enabled(&c->scene->node, false);
|
||||
} else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) {
|
||||
} 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_monocle_hide = false;
|
||||
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 -
|
||||
(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)
|
||||
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)) {
|
||||
c->geom = geo;
|
||||
c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width);
|
||||
c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height);
|
||||
c->geom.width = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.width);
|
||||
c->geom.height = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.height);
|
||||
} else { // 这里会限制不允许窗口划出屏幕
|
||||
c->geom = geo;
|
||||
applybounds(
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) {
|
|||
double percent = 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)
|
||||
wlr_scene_node_for_each_buffer(&l->scene->node,
|
||||
|
|
@ -277,10 +277,10 @@ void layer_animation_next_tick(LayerSurface *l) {
|
|||
double opacity_eased_progress =
|
||||
find_animation_curve_at(animation_passed, OPAFADEIN);
|
||||
|
||||
double opacity =
|
||||
MIN(config.fadein_begin_opacity +
|
||||
opacity_eased_progress * (1.0 - config.fadein_begin_opacity),
|
||||
1.0f);
|
||||
double opacity = MANGO_MIN(config.fadein_begin_opacity +
|
||||
opacity_eased_progress *
|
||||
(1.0 - config.fadein_begin_opacity),
|
||||
1.0f);
|
||||
|
||||
if (config.animation_fade_in)
|
||||
wlr_scene_node_for_each_buffer(&l->scene->node,
|
||||
|
|
|
|||
|
|
@ -23,30 +23,32 @@ void set_tagin_animation(Monitor *m, Client *c) {
|
|||
|
||||
c->animainit_geom.x = config.tag_animation_direction == VERTICAL
|
||||
? c->animation.current.x
|
||||
: MAX(c->mon->m.x + c->mon->m.width,
|
||||
c->geom.x + c->mon->m.width);
|
||||
: MANGO_MAX(c->mon->m.x + c->mon->m.width,
|
||||
c->geom.x + c->mon->m.width);
|
||||
c->animainit_geom.y = config.tag_animation_direction == VERTICAL
|
||||
? MAX(c->mon->m.y + c->mon->m.height,
|
||||
c->geom.y + c->mon->m.height)
|
||||
? MANGO_MAX(c->mon->m.y + c->mon->m.height,
|
||||
c->geom.y + c->mon->m.height)
|
||||
: c->animation.current.y;
|
||||
|
||||
} else {
|
||||
|
||||
c->animainit_geom.x =
|
||||
config.tag_animation_direction == VERTICAL
|
||||
? c->animation.current.x
|
||||
: MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width);
|
||||
c->animainit_geom.y =
|
||||
config.tag_animation_direction == VERTICAL
|
||||
? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height)
|
||||
: c->animation.current.y;
|
||||
c->animainit_geom.x = config.tag_animation_direction == VERTICAL
|
||||
? c->animation.current.x
|
||||
: MANGO_MIN(m->m.x - c->geom.width,
|
||||
c->geom.x - c->mon->m.width);
|
||||
c->animainit_geom.y = config.tag_animation_direction == VERTICAL
|
||||
? MANGO_MIN(m->m.y - c->geom.height,
|
||||
c->geom.y - c->mon->m.height)
|
||||
: c->animation.current.y;
|
||||
}
|
||||
}
|
||||
|
||||
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_monocle_hide = false;
|
||||
wlr_scene_node_set_enabled(&c->scene->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;
|
||||
if (going_forward) {
|
||||
c->pending = c->geom;
|
||||
c->pending.x =
|
||||
config.tag_animation_direction == VERTICAL
|
||||
? c->animation.current.x
|
||||
: MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width);
|
||||
c->pending.x = config.tag_animation_direction == VERTICAL
|
||||
? c->animation.current.x
|
||||
: MANGO_MIN(c->mon->m.x - c->geom.width,
|
||||
c->geom.x - c->mon->m.width);
|
||||
c->pending.y = config.tag_animation_direction == VERTICAL
|
||||
? MIN(c->mon->m.y - c->geom.height,
|
||||
c->geom.y - c->mon->m.height)
|
||||
? MANGO_MIN(c->mon->m.y - c->geom.height,
|
||||
c->geom.y - c->mon->m.height)
|
||||
: c->animation.current.y;
|
||||
|
||||
resize(c, c->geom, 0);
|
||||
|
|
@ -98,11 +100,11 @@ void set_tagout_animation(Monitor *m, Client *c) {
|
|||
c->pending = c->geom;
|
||||
c->pending.x = config.tag_animation_direction == VERTICAL
|
||||
? c->animation.current.x
|
||||
: MAX(c->mon->m.x + c->mon->m.width,
|
||||
c->geom.x + c->mon->m.width);
|
||||
: MANGO_MAX(c->mon->m.x + c->mon->m.width,
|
||||
c->geom.x + c->mon->m.width);
|
||||
c->pending.y = config.tag_animation_direction == VERTICAL
|
||||
? MAX(c->mon->m.y + c->mon->m.height,
|
||||
c->geom.y + c->mon->m.height)
|
||||
? MANGO_MAX(c->mon->m.y + c->mon->m.height,
|
||||
c->geom.y + c->mon->m.height)
|
||||
: c->animation.current.y;
|
||||
resize(c, c->geom, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ 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;
|
||||
|
|
@ -310,6 +311,7 @@ typedef struct {
|
|||
uint32_t gappoh;
|
||||
uint32_t gappov;
|
||||
uint32_t borderpx;
|
||||
uint32_t tab_bar_height;
|
||||
float scratchpad_width_ratio;
|
||||
float scratchpad_height_ratio;
|
||||
float rootcolor[4];
|
||||
|
|
@ -386,6 +388,8 @@ typedef struct {
|
|||
|
||||
struct xkb_context *ctx;
|
||||
struct xkb_keymap *keymap;
|
||||
DecorateDrawData jumplabeldata;
|
||||
DecorateDrawData tabdata;
|
||||
} Config;
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
|
@ -1701,6 +1708,146 @@ 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, "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) {
|
||||
config->disable_while_typing = atoi(value);
|
||||
} 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);
|
||||
} else if (strcmp(key, "borderpx") == 0) {
|
||||
config->borderpx = atoi(value);
|
||||
} else if (strcmp(key, "tab_bar_height") == 0) {
|
||||
config->tab_bar_height = atoi(value);
|
||||
} else if (strcmp(key, "rootcolor") == 0) {
|
||||
int64_t color = parse_color(value);
|
||||
if (color == -1) {
|
||||
|
|
@ -3160,6 +3309,16 @@ void free_config(void) {
|
|||
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) {
|
||||
free(config.tablet_map_to_mon);
|
||||
config.tablet_map_to_mon = NULL;
|
||||
|
|
@ -3321,10 +3480,27 @@ void override_config(void) {
|
|||
config.scratchpad_height_ratio =
|
||||
CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f);
|
||||
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.focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f);
|
||||
config.unfocused_opacity =
|
||||
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() {
|
||||
|
|
@ -3363,7 +3539,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;
|
||||
|
|
@ -3413,6 +3588,7 @@ void set_value_default() {
|
|||
config.idleinhibit_ignore_visible = 0;
|
||||
|
||||
config.borderpx = 4;
|
||||
config.tab_bar_height = 50;
|
||||
config.overviewgappi = 5;
|
||||
config.overviewgappo = 30;
|
||||
config.cursor_hide_timeout = 0;
|
||||
|
|
@ -3477,6 +3653,56 @@ void set_value_default() {
|
|||
config.animation_curve_opafadeout[2] = 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[1] = 0x32 / 255.0f;
|
||||
config.rootcolor[2] = 0x32 / 255.0f;
|
||||
|
|
@ -3589,6 +3815,8 @@ bool parse_config(void) {
|
|||
config.tag_rules = NULL;
|
||||
config.tag_rules_count = 0;
|
||||
config.cursor_theme = NULL;
|
||||
config.jumplabeldata.font_desc = NULL;
|
||||
config.tabdata.font_desc = NULL;
|
||||
config.tablet_map_to_mon = NULL;
|
||||
strcpy(config.keymode, "default");
|
||||
|
||||
|
|
@ -3726,6 +3954,10 @@ void reapply_property(void) {
|
|||
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->splitindicator[0], config.splitcolor);
|
||||
wlr_scene_rect_set_color(c->splitindicator[1], config.splitcolor);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ int32_t focusdir(const Arg *arg) {
|
|||
|
||||
Client *c = NULL;
|
||||
c = direction_select(arg);
|
||||
|
||||
if (!selmon->isoverview)
|
||||
c = get_focused_stack_client(c, arg->tc);
|
||||
if (c) {
|
||||
|
|
@ -265,7 +266,7 @@ int32_t incnmaster(const Arg *arg) {
|
|||
if (!arg || !selmon)
|
||||
return 0;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -737,12 +738,12 @@ int32_t smartmovewin(const Arg *arg) {
|
|||
continue;
|
||||
buttom = tc->geom.y + tc->geom.height + config.gappiv;
|
||||
if (top > buttom && ny < buttom) {
|
||||
tar = MAX(tar, buttom);
|
||||
tar = MANGO_MAX(tar, buttom);
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
case DOWN:
|
||||
tar = 99999;
|
||||
|
|
@ -757,12 +758,12 @@ int32_t smartmovewin(const Arg *arg) {
|
|||
continue;
|
||||
top = tc->geom.y - config.gappiv;
|
||||
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 = MIN(ny, c->mon->w.y + c->mon->w.height - c->geom.height -
|
||||
c->mon->gappov);
|
||||
ny = MANGO_MIN(ny, c->mon->w.y + c->mon->w.height - c->geom.height -
|
||||
c->mon->gappov);
|
||||
break;
|
||||
case LEFT:
|
||||
tar = -99999;
|
||||
|
|
@ -777,12 +778,12 @@ int32_t smartmovewin(const Arg *arg) {
|
|||
continue;
|
||||
right = tc->geom.x + tc->geom.width + config.gappih;
|
||||
if (left > right && nx < right) {
|
||||
tar = MAX(tar, right);
|
||||
tar = MANGO_MAX(tar, right);
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
case RIGHT:
|
||||
tar = 99999;
|
||||
|
|
@ -796,12 +797,12 @@ int32_t smartmovewin(const Arg *arg) {
|
|||
continue;
|
||||
left = tc->geom.x - config.gappih;
|
||||
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 = MIN(nx, c->mon->w.x + c->mon->w.width - c->geom.width -
|
||||
c->mon->gappoh);
|
||||
nx = MANGO_MIN(nx, c->mon->w.x + c->mon->w.width - c->geom.width -
|
||||
c->mon->gappoh);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -829,7 +830,7 @@ int32_t smartresizewin(const Arg *arg) {
|
|||
switch (arg->i) {
|
||||
case UP:
|
||||
nh -= selmon->w.height / 8;
|
||||
nh = MAX(nh, selmon->w.height / 10);
|
||||
nh = MANGO_MAX(nh, selmon->w.height / 10);
|
||||
break;
|
||||
case DOWN:
|
||||
tar = -99999;
|
||||
|
|
@ -844,7 +845,7 @@ int32_t smartresizewin(const Arg *arg) {
|
|||
continue;
|
||||
top = tc->geom.y - config.gappiv;
|
||||
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;
|
||||
|
|
@ -853,7 +854,7 @@ int32_t smartresizewin(const Arg *arg) {
|
|||
break;
|
||||
case LEFT:
|
||||
nw -= selmon->w.width / 16;
|
||||
nw = MAX(nw, selmon->w.width / 10);
|
||||
nw = MANGO_MAX(nw, selmon->w.width / 10);
|
||||
break;
|
||||
case RIGHT:
|
||||
tar = 99999;
|
||||
|
|
@ -867,7 +868,7 @@ int32_t smartresizewin(const Arg *arg) {
|
|||
continue;
|
||||
left = tc->geom.x - config.gappih;
|
||||
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) {
|
||||
for (jk = 0; jk < config.circle_layout_count; jk++) {
|
||||
|
||||
len = MAX(
|
||||
len = MANGO_MAX(
|
||||
strlen(config.circle_layout[jk]),
|
||||
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++) {
|
||||
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) {
|
||||
selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[ji];
|
||||
|
||||
|
|
@ -1738,6 +1740,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) &&
|
||||
|
|
@ -1782,6 +1788,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 &&
|
||||
|
|
@ -1795,6 +1802,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;
|
||||
}
|
||||
|
||||
|
|
|
|||
845
src/draw/text-node.c
Normal file
845
src/draw/text-node.c
Normal 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
166
src/draw/text-node.h
Normal 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
|
||||
|
|
@ -188,8 +188,12 @@ Client *find_client_by_direction(Client *tc, const Arg *arg,
|
|||
continue;
|
||||
if (!findfloating && c->isfloating)
|
||||
continue;
|
||||
if (c->is_monocle_hide)
|
||||
continue;
|
||||
if (c->isunglobal)
|
||||
continue;
|
||||
if (c->is_monocle_hide)
|
||||
continue;
|
||||
if (!config.focus_cross_monitor && c->mon != tc->mon)
|
||||
continue;
|
||||
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;
|
||||
|
||||
wl_list_for_each(tc, &fstack, flink) {
|
||||
if (tc->iskilling || tc->isunglobal)
|
||||
if (tc->iskilling || tc->isunglobal || tc->is_monocle_hide)
|
||||
continue;
|
||||
if (!VISIBLEON(tc, sc->mon))
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,14 @@ bool is_scroller_layout(Monitor *m) {
|
|||
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) {
|
||||
|
||||
if (m->pertag->ltidxs[m->pertag->curtag]->id == CENTER_TILE)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
int32_t offsety, uint32_t time,
|
||||
int32_t type) {
|
||||
|
|
@ -1128,6 +1143,20 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
|
|||
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)) {
|
||||
c->tags = m->tagset[m->seltags];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,7 +259,8 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
|
|||
if (node->client) {
|
||||
if (!node->client->isfullscreen &&
|
||||
!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);
|
||||
}
|
||||
}
|
||||
|
|
@ -273,12 +274,12 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
|
|||
node->container_w = aw;
|
||||
node->container_h = ah;
|
||||
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->second, ax + w1 + gap_h, ay, aw - w1 - gap_h, ah,
|
||||
gap_h, gap_v);
|
||||
} 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->second, ax, ay + h1 + gap_v, aw, ah - h1 - gap_v,
|
||||
gap_h, gap_v);
|
||||
|
|
@ -357,7 +358,7 @@ static void dwindle_resize_client(Monitor *m, Client *c) {
|
|||
return;
|
||||
|
||||
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);
|
||||
if (config.dwindle_smart_resize) {
|
||||
/* 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) {
|
||||
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);
|
||||
if (config.dwindle_smart_resize) {
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
h_node->ratio = CLAMP_FLOAT(h_node->ratio + delta, 0.05f, 0.95f);
|
||||
}
|
||||
|
||||
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;
|
||||
v_node->ratio = CLAMP_FLOAT(v_node->ratio + delta, 0.05f, 0.95f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ void tile(Monitor *m) {
|
|||
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
|
||||
continue;
|
||||
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) {
|
||||
h = master_surplus_height * c->master_inner_per /
|
||||
master_surplus_ratio;
|
||||
|
|
@ -179,7 +179,7 @@ void right_tile(Monitor *m) {
|
|||
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
|
||||
continue;
|
||||
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) {
|
||||
h = master_surplus_height * c->master_inner_per /
|
||||
master_surplus_ratio;
|
||||
|
|
@ -345,7 +345,7 @@ void center_tile(Monitor *m) {
|
|||
|
||||
if (i < nmasters) {
|
||||
// 主区域窗口
|
||||
r = MIN(n, nmasters) - i;
|
||||
r = MANGO_MIN(n, nmasters) - i;
|
||||
if (c->master_inner_per > 0.0f) {
|
||||
h = master_surplus_height * c->master_inner_per /
|
||||
master_surplus_ratio;
|
||||
|
|
@ -518,8 +518,8 @@ void deck(Monitor *m) {
|
|||
continue;
|
||||
if (i < nmasters) {
|
||||
c->master_mfact_per = mfact;
|
||||
int32_t h =
|
||||
(m->w.height - 2 * cur_gappov - my) / (MIN(n, nmasters) - i);
|
||||
int32_t h = (m->w.height - 2 * cur_gappov - my) /
|
||||
(MANGO_MIN(n, nmasters) - i);
|
||||
client_tile_resize(c,
|
||||
(struct wlr_box){.x = m->w.x + cur_gappoh,
|
||||
.y = m->w.y + cur_gappov + my,
|
||||
|
|
@ -545,32 +545,83 @@ void deck(Monitor *m) {
|
|||
}
|
||||
}
|
||||
|
||||
void // 17
|
||||
monocle(Monitor *m) {
|
||||
Client *c = NULL;
|
||||
void monocle(Monitor *m) {
|
||||
Client *c = NULL, *fc = NULL;
|
||||
struct wlr_box geom;
|
||||
|
||||
int32_t cur_gappov = enablegaps ? m->gappov : 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
|
||||
? 0
|
||||
: cur_gappoh;
|
||||
cur_gappov = config.smartgaps && m->visible_fake_tiling_clients == 1
|
||||
? 0
|
||||
: cur_gappov;
|
||||
if (config.smartgaps && m->visible_fake_tiling_clients == 1) {
|
||||
cur_gappov = cur_gappoh = cur_gapiv = cur_gapih = 0;
|
||||
}
|
||||
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
|
||||
int n = m->visible_fake_tiling_clients;
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
wl_list_for_each(c, &fstack, flink) {
|
||||
if (c->iskilling || c->isunglobal || !ISFAKETILED(c))
|
||||
continue;
|
||||
if (VISIBLEON(c, m)) {
|
||||
fc = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 1) {
|
||||
geom.x = m->w.x + cur_gappoh;
|
||||
geom.y = m->w.y + cur_gappov;
|
||||
geom.width = m->w.width - 2 * cur_gappoh;
|
||||
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);
|
||||
}
|
||||
|
||||
// 网格布局窗口大小和位置计算
|
||||
|
|
|
|||
|
|
@ -353,10 +353,66 @@ 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) && !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) {
|
||||
|
||||
if (config.ov_no_resize) {
|
||||
overview_scale(m);
|
||||
} else {
|
||||
overview_resize(m);
|
||||
}
|
||||
|
||||
if (m->is_jump_mode) {
|
||||
create_jump_hints(m);
|
||||
}
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ void vertical_tile(Monitor *m) {
|
|||
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
|
||||
continue;
|
||||
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) {
|
||||
w = master_surplus_width * c->master_inner_per /
|
||||
master_surplus_ratio;
|
||||
|
|
@ -155,8 +155,8 @@ void vertical_deck(Monitor *m) {
|
|||
continue;
|
||||
if (i < nmasters) {
|
||||
c->master_mfact_per = mfact;
|
||||
int32_t w =
|
||||
(m->w.width - 2 * cur_gappoh - mx) / (MIN(n, nmasters) - i);
|
||||
int32_t w = (m->w.width - 2 * cur_gappoh - mx) /
|
||||
(MANGO_MIN(n, nmasters) - i);
|
||||
client_tile_resize(c,
|
||||
(struct wlr_box){.x = m->w.x + cur_gappoh + mx,
|
||||
.y = m->w.y + cur_gappov,
|
||||
|
|
|
|||
107
src/mango.c
107
src/mango.c
|
|
@ -94,10 +94,11 @@
|
|||
#include <xcb/xcb_icccm.h>
|
||||
#endif
|
||||
#include "common/util.h"
|
||||
#include "draw/text-node.h"
|
||||
|
||||
/* macros */
|
||||
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define MANGO_MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||
#define MANGO_MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define GEZERO(A) ((A) >= 0 ? (A) : 0)
|
||||
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
|
||||
#define INSIDEMON(A) \
|
||||
|
|
@ -165,6 +166,7 @@ enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向
|
|||
enum {
|
||||
LyrBg,
|
||||
LyrBottom,
|
||||
LyrDecorate,
|
||||
LyrTile,
|
||||
LyrTop,
|
||||
LyrFadeOut,
|
||||
|
|
@ -173,6 +175,9 @@ enum {
|
|||
LyrBlock,
|
||||
NUM_LAYERS
|
||||
}; /* scene layers */
|
||||
|
||||
enum mango_node_type { MANGO_TITLE_NODE, MANGO_jump_label_node };
|
||||
|
||||
#ifdef XWAYLAND
|
||||
enum {
|
||||
NetWMWindowTypeDialog,
|
||||
|
|
@ -239,6 +244,11 @@ typedef struct {
|
|||
Client *tc;
|
||||
} Arg;
|
||||
|
||||
typedef struct {
|
||||
enum mango_node_type type;
|
||||
void *node_data;
|
||||
} MangoNodeData;
|
||||
|
||||
typedef struct {
|
||||
uint32_t mod;
|
||||
uint32_t button;
|
||||
|
|
@ -262,8 +272,8 @@ typedef struct {
|
|||
struct wl_list link;
|
||||
struct wlr_input_device *wlr_device;
|
||||
struct libinput_device *libinput_device;
|
||||
struct wl_listener destroy_listener; // 用于监听设备销毁事件
|
||||
void *device_data; // 新增:指向设备特定数据(如 Switch)
|
||||
struct wl_listener destroy_listener;
|
||||
void *device_data;
|
||||
} InputDevice;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -329,6 +339,8 @@ struct Client {
|
|||
struct wlr_ext_image_capture_source_v1 *image_capture_source;
|
||||
|
||||
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 flink;
|
||||
struct wl_list fadeout_link;
|
||||
|
|
@ -395,6 +407,7 @@ struct Client {
|
|||
int32_t istagswitching;
|
||||
int32_t isnamedscratchpad;
|
||||
int32_t shield_when_capture;
|
||||
bool is_monocle_hide;
|
||||
bool is_pending_open_animation;
|
||||
bool is_restoring_from_ov;
|
||||
float scroller_proportion;
|
||||
|
|
@ -434,6 +447,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 +566,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;
|
||||
|
|
@ -847,6 +862,7 @@ static struct wlr_scene_tree *
|
|||
wlr_scene_tree_snapshot(struct wlr_scene_node *node,
|
||||
struct wlr_scene_tree *parent);
|
||||
static bool is_scroller_layout(Monitor *m);
|
||||
static bool is_monocle_layout(Monitor *m);
|
||||
static bool is_centertile_layout(Monitor *m);
|
||||
static void create_output(struct wlr_backend *backend, void *data);
|
||||
static void get_layout_abbr(char *abbr, const char *full_name);
|
||||
|
|
@ -911,6 +927,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"
|
||||
|
|
@ -1143,8 +1163,8 @@ void client_change_mon(Client *c, Monitor *m) {
|
|||
|
||||
void applybounds(Client *c, struct wlr_box *bbox) {
|
||||
/* set minimum possible */
|
||||
c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width);
|
||||
c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height);
|
||||
c->geom.width = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.width);
|
||||
c->geom.height = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.height);
|
||||
|
||||
if (c->geom.x >= bbox->x + bbox->width)
|
||||
c->geom.x = bbox->x + bbox->width - c->geom.width;
|
||||
|
|
@ -1275,6 +1295,10 @@ void swallow(Client *c, Client *w) {
|
|||
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->flink, &c->flink);
|
||||
|
|
@ -1567,7 +1591,7 @@ void set_float_malposition(Client *tc) {
|
|||
y = tc->geom.y;
|
||||
xreverse = 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) {
|
||||
if (c->isfloating && c != tc && VISIBLEON(c, tc->mon) &&
|
||||
|
|
@ -2382,6 +2406,17 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
|
|||
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按键状态
|
||||
hard_keyboard = &kb_group->wlr_group->keyboard;
|
||||
|
|
@ -2581,6 +2616,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) {
|
||||
|
|
@ -3800,17 +3837,17 @@ void focusclient(Client *c, int32_t lift) {
|
|||
|
||||
// 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
|
||||
wl_list_remove(&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
|
||||
c->isurgent = 0;
|
||||
}
|
||||
|
|
@ -4207,6 +4244,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 */
|
||||
|
|
@ -4288,6 +4346,9 @@ void locksession(struct wl_listener *listener, void *data) {
|
|||
void init_client_properties(Client *c) {
|
||||
c->grid_col_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->drop_direction = UNDIR;
|
||||
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) {
|
||||
selmon->gappoh = MAX(oh, 0);
|
||||
selmon->gappov = MAX(ov, 0);
|
||||
selmon->gappih = MAX(ih, 0);
|
||||
selmon->gappiv = MAX(iv, 0);
|
||||
selmon->gappoh = MANGO_MAX(oh, 0);
|
||||
selmon->gappov = MANGO_MAX(ov, 0);
|
||||
selmon->gappih = MANGO_MAX(ih, 0);
|
||||
selmon->gappiv = MANGO_MAX(iv, 0);
|
||||
arrange(selmon, false, false);
|
||||
}
|
||||
|
||||
|
|
@ -6534,6 +6595,15 @@ void unmapnotify(struct wl_listener *listener, void *data) {
|
|||
|
||||
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);
|
||||
printstatus(IPC_WATCH_ARRANGGE);
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
|
|
@ -6681,6 +6751,7 @@ void updatetitle(struct wl_listener *listener, void *data) {
|
|||
|
||||
const char *title;
|
||||
title = client_get_title(c);
|
||||
mango_tab_bar_node_update(c->tab_bar_node, title, 1.0);
|
||||
if (title && c->foreign_toplevel)
|
||||
wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title);
|
||||
if (title && c->ext_foreign_toplevel) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue