mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-07-05 00:06:20 -04:00
First step toward titlebars
This commit is contained in:
parent
8216cacb3b
commit
602ff97410
3 changed files with 238 additions and 6 deletions
|
|
@ -450,7 +450,6 @@ void apply_split_border(Client *c, bool hit_no_border) {
|
|||
}
|
||||
|
||||
struct wlr_box fullgeom = c->animation.current;
|
||||
// 一但在GEZERO如果使用无符号,那么其他数据也会转换为无符号导致没有负数出错
|
||||
int32_t bw = (int32_t)c->bw;
|
||||
|
||||
int32_t right_offset, bottom_offset, left_offset, top_offset;
|
||||
|
|
@ -503,6 +502,75 @@ void apply_split_border(Client *c, bool hit_no_border) {
|
|||
border_right_y);
|
||||
}
|
||||
|
||||
static int32_t titlebar_active_height(void) {
|
||||
return config.enable_titlebars ? (int32_t)config.titlebar_height : 0;
|
||||
}
|
||||
|
||||
void update_titlebar_hover(Client *c);
|
||||
|
||||
void apply_titlebar(Client *c, int32_t rect_width,
|
||||
enum corner_location corners) {
|
||||
int32_t tb = titlebar_active_height();
|
||||
bool show_titlebar = tb > 0 && !c->isfullscreen;
|
||||
if (!c->titlebar_bg)
|
||||
return;
|
||||
wlr_scene_node_set_enabled(&c->titlebar_bg->node, show_titlebar);
|
||||
if (show_titlebar) {
|
||||
int32_t tb_margin = (int32_t)config.titlebar_button_margin;
|
||||
int32_t tb_btn_size = (int32_t)config.titlebar_button_size;
|
||||
|
||||
wlr_scene_rect_set_size(c->titlebar_bg, rect_width, tb);
|
||||
wlr_scene_node_set_position(&c->titlebar_bg->node, 0, 0);
|
||||
wlr_scene_rect_set_corner_radius(c->titlebar_bg, config.border_radius,
|
||||
corners & ~CORNER_LOCATION_BOTTOM);
|
||||
|
||||
if (c->titlebar_close) {
|
||||
int32_t btn_x = rect_width - tb_margin - tb_btn_size;
|
||||
int32_t btn_y = tb_margin;
|
||||
int32_t btn_h = tb - 2 * tb_margin;
|
||||
wlr_scene_rect_set_size(c->titlebar_close, tb_btn_size, btn_h);
|
||||
wlr_scene_node_set_position(&c->titlebar_close->node, btn_x, btn_y);
|
||||
update_titlebar_hover(c);
|
||||
wlr_scene_node_set_enabled(&c->titlebar_close->node, true);
|
||||
}
|
||||
} else if (c->titlebar_close) {
|
||||
wlr_scene_node_set_enabled(&c->titlebar_close->node, false);
|
||||
}
|
||||
}
|
||||
|
||||
void update_titlebar_hover(Client *c) {
|
||||
if (!c || !c->titlebar_close || !c->titlebar_bg)
|
||||
return;
|
||||
int32_t tb = titlebar_active_height();
|
||||
if (tb <= 0 || c->isfullscreen) {
|
||||
wlr_scene_node_set_enabled(&c->titlebar_close->node, false);
|
||||
return;
|
||||
}
|
||||
wlr_scene_node_set_enabled(&c->titlebar_close->node, true);
|
||||
|
||||
int32_t tb_margin = (int32_t)config.titlebar_button_margin;
|
||||
int32_t tb_btn_size = (int32_t)config.titlebar_button_size;
|
||||
int32_t btn_x = c->animation.current.width - tb_margin - tb_btn_size;
|
||||
int32_t btn_y = tb_margin;
|
||||
int32_t btn_h = tb - 2 * tb_margin;
|
||||
|
||||
bool hover = cursor->x >= c->animation.current.x + btn_x &&
|
||||
cursor->x < c->animation.current.x + btn_x + tb_btn_size &&
|
||||
cursor->y >= c->animation.current.y + btn_y &&
|
||||
cursor->y < c->animation.current.y + btn_y + btn_h;
|
||||
|
||||
if (hover) {
|
||||
float hover_color[4] = {config.title_close_color[0] * 0.5f + 0.5f,
|
||||
config.title_close_color[1] * 0.5f + 0.5f,
|
||||
config.title_close_color[2] * 0.5f + 0.5f,
|
||||
config.title_close_color[3]};
|
||||
wlr_scene_rect_set_color(c->titlebar_close, hover_color);
|
||||
} else {
|
||||
wlr_scene_rect_set_color(c->titlebar_close, config.title_close_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply_border(Client *c) {
|
||||
if (!c || c->iskilling || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
|
@ -536,8 +604,10 @@ void apply_border(Client *c) {
|
|||
c->fake_no_border = true;
|
||||
} else if (hit_no_border && !config.smartgaps) {
|
||||
wlr_scene_rect_set_size(c->border, 0, 0);
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw,
|
||||
c->bw + titlebar_active_height());
|
||||
c->fake_no_border = true;
|
||||
apply_titlebar(c, c->animation.current.width, current_corner_location);
|
||||
return;
|
||||
} else if (!c->isfullscreen && VISIBLEON(c, c->mon)) {
|
||||
c->bw = c->isnoborder ? 0 : config.borderpx;
|
||||
|
|
@ -606,12 +676,16 @@ void apply_border(Client *c) {
|
|||
.corners = current_corner_location,
|
||||
};
|
||||
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
int32_t tb = titlebar_active_height();
|
||||
int32_t surf_y_off = tb > 0 ? tb : c->bw;
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, surf_y_off);
|
||||
wlr_scene_rect_set_size(c->border, rect_width, rect_height);
|
||||
wlr_scene_node_set_position(&c->border->node, rect_x, rect_y);
|
||||
wlr_scene_rect_set_corner_radius(c->border, config.border_radius,
|
||||
current_corner_location);
|
||||
wlr_scene_rect_set_clipped_region(c->border, clipped_region);
|
||||
|
||||
apply_titlebar(c, c->animation.current.width, current_corner_location);
|
||||
}
|
||||
|
||||
struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) {
|
||||
|
|
@ -892,6 +966,7 @@ void client_apply_clip(Client *c, float factor) {
|
|||
c->geom;
|
||||
|
||||
client_get_clip(c, &clip_box);
|
||||
clip_box.height = GEZERO(clip_box.height - titlebar_active_height());
|
||||
|
||||
offset = clip_to_hide(c, &clip_box);
|
||||
|
||||
|
|
@ -924,7 +999,7 @@ void client_apply_clip(Client *c, float factor) {
|
|||
.x = geometry.x,
|
||||
.y = geometry.y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.height = height - titlebar_active_height(),
|
||||
};
|
||||
|
||||
if (client_is_x11(c)) {
|
||||
|
|
@ -1364,7 +1439,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
|
|||
// c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局
|
||||
if (!c->mon->isoverview || !config.ov_no_resize) {
|
||||
c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw,
|
||||
c->geom.height - 2 * c->bw);
|
||||
c->geom.height - 2 * c->bw - titlebar_active_height());
|
||||
}
|
||||
|
||||
if (c->configure_serial != 0) {
|
||||
|
|
@ -1382,6 +1457,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
|
|||
client_draw_shadow(c);
|
||||
apply_border(c);
|
||||
client_get_clip(c, &clip);
|
||||
clip.height = GEZERO(clip.height - titlebar_active_height());
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,6 +346,14 @@ typedef struct {
|
|||
float globalcolor[4];
|
||||
float overlaycolor[4];
|
||||
|
||||
int32_t enable_titlebars;
|
||||
uint32_t titlebar_height;
|
||||
uint32_t titlebar_button_size;
|
||||
uint32_t titlebar_button_margin;
|
||||
float title_color[4];
|
||||
float title_unfocused_color[4];
|
||||
float title_close_color[4];
|
||||
|
||||
int32_t log_level;
|
||||
uint32_t capslock;
|
||||
|
||||
|
|
@ -2078,6 +2086,47 @@ bool parse_option(Config *config, char *key, char *value) {
|
|||
} else {
|
||||
convert_hex_to_rgba(config->overlaycolor, color);
|
||||
}
|
||||
} else if (strcmp(key, "enable_titlebars") == 0) {
|
||||
config->enable_titlebars = atoi(value);
|
||||
} else if (strcmp(key, "titlebar_height") == 0) {
|
||||
config->titlebar_height = atoi(value);
|
||||
} else if (strcmp(key, "titlebar_button_size") == 0) {
|
||||
config->titlebar_button_size = atoi(value);
|
||||
} else if (strcmp(key, "titlebar_button_margin") == 0) {
|
||||
config->titlebar_button_margin = atoi(value);
|
||||
} else if (strcmp(key, "title_color") == 0) {
|
||||
int64_t color = parse_color(value);
|
||||
if (color == -1) {
|
||||
fprintf(stderr,
|
||||
"\033[1m\033[31m[ERROR]:\033[33m Invalid title_color "
|
||||
"format: %s\n",
|
||||
value);
|
||||
return false;
|
||||
} else {
|
||||
convert_hex_to_rgba(config->title_color, color);
|
||||
}
|
||||
} else if (strcmp(key, "title_unfocused_color") == 0) {
|
||||
int64_t color = parse_color(value);
|
||||
if (color == -1) {
|
||||
fprintf(stderr,
|
||||
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
|
||||
"title_unfocused_color format: %s\n",
|
||||
value);
|
||||
return false;
|
||||
} else {
|
||||
convert_hex_to_rgba(config->title_unfocused_color, color);
|
||||
}
|
||||
} else if (strcmp(key, "title_close_color") == 0) {
|
||||
int64_t color = parse_color(value);
|
||||
if (color == -1) {
|
||||
fprintf(stderr,
|
||||
"\033[1m\033[31m[ERROR]:\033[33m Invalid title_close_color "
|
||||
"format: %s\n",
|
||||
value);
|
||||
return false;
|
||||
} else {
|
||||
convert_hex_to_rgba(config->title_close_color, color);
|
||||
}
|
||||
} else if (strcmp(key, "monitorrule") == 0) {
|
||||
config->monitor_rules =
|
||||
realloc(config->monitor_rules, (config->monitor_rules_count + 1) *
|
||||
|
|
@ -3597,7 +3646,6 @@ void override_config(void) {
|
|||
config.focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f);
|
||||
config.unfocused_opacity =
|
||||
CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f);
|
||||
|
||||
config.tabdata.border_width =
|
||||
CLAMP_INT(config.tabdata.border_width, 0, 100);
|
||||
config.tabdata.corner_radius =
|
||||
|
|
@ -3613,6 +3661,12 @@ void override_config(void) {
|
|||
CLAMP_INT(config.jumplabeldata.padding_x, 0, 100);
|
||||
config.jumplabeldata.padding_y =
|
||||
CLAMP_INT(config.jumplabeldata.padding_y, 0, 100);
|
||||
config.enable_titlebars = CLAMP_INT(config.enable_titlebars, 0, 1);
|
||||
config.titlebar_height = CLAMP_INT(config.titlebar_height, 10, 200);
|
||||
config.titlebar_button_size =
|
||||
CLAMP_INT(config.titlebar_button_size, 4, 100);
|
||||
config.titlebar_button_margin =
|
||||
CLAMP_INT(config.titlebar_button_margin, 0, 50);
|
||||
}
|
||||
|
||||
void set_value_default() {
|
||||
|
|
@ -3879,6 +3933,23 @@ void set_value_default() {
|
|||
config.overlaycolor[1] = 0xa5 / 255.0f;
|
||||
config.overlaycolor[2] = 0x7c / 255.0f;
|
||||
config.overlaycolor[3] = 1.0f;
|
||||
|
||||
config.enable_titlebars = 0;
|
||||
config.titlebar_height = 30;
|
||||
config.titlebar_button_size = 16;
|
||||
config.titlebar_button_margin = 4;
|
||||
config.title_color[0] = 0xc6 / 255.0f;
|
||||
config.title_color[1] = 0x6b / 255.0f;
|
||||
config.title_color[2] = 0x25 / 255.0f;
|
||||
config.title_color[3] = 1.0f;
|
||||
config.title_unfocused_color[0] = 0x44 / 255.0f;
|
||||
config.title_unfocused_color[1] = 0x44 / 255.0f;
|
||||
config.title_unfocused_color[2] = 0x44 / 255.0f;
|
||||
config.title_unfocused_color[3] = 1.0f;
|
||||
config.title_close_color[0] = 0xad / 255.0f;
|
||||
config.title_close_color[1] = 0x40 / 255.0f;
|
||||
config.title_close_color[2] = 0x1f / 255.0f;
|
||||
config.title_close_color[3] = 1.0f;
|
||||
}
|
||||
|
||||
void set_default_key_bindings(Config *config) {
|
||||
|
|
|
|||
85
src/mango.c
85
src/mango.c
|
|
@ -339,6 +339,8 @@ struct Client {
|
|||
struct wlr_scene_tree *overview_scene_surface;
|
||||
struct mango_jump_label_node *jump_label_node;
|
||||
struct mango_tab_bar_node *tab_bar_node;
|
||||
struct wlr_scene_rect *titlebar_bg;
|
||||
struct wlr_scene_rect *titlebar_close;
|
||||
struct wl_list link;
|
||||
struct wl_list flink;
|
||||
struct wl_list fadeout_link;
|
||||
|
|
@ -984,6 +986,7 @@ static int32_t rzcorner;
|
|||
static int32_t grabcx, grabcy; /* client-relative */
|
||||
static int32_t drag_begin_cursorx, drag_begin_cursory; /* client-relative */
|
||||
static bool start_drag_window = false;
|
||||
static Client *hovered_client = NULL;
|
||||
static int32_t last_apply_drap_time = 0;
|
||||
|
||||
static struct wlr_output_layout *output_layout;
|
||||
|
|
@ -2411,6 +2414,36 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
|
|||
|
||||
mods = mods | hard_mods;
|
||||
|
||||
if (config.enable_titlebars && event->button == BTN_LEFT && c &&
|
||||
!c->isfullscreen && !client_is_unmanaged(c)) {
|
||||
int32_t tb_height = (int32_t)config.titlebar_height;
|
||||
if (cursor->y >= c->geom.y && cursor->y < c->geom.y + tb_height) {
|
||||
int32_t tb_margin = (int32_t)config.titlebar_button_margin;
|
||||
int32_t tb_btn_size = (int32_t)config.titlebar_button_size;
|
||||
int32_t close_x =
|
||||
c->geom.x + c->geom.width - tb_margin - tb_btn_size;
|
||||
int32_t close_y = c->geom.y + tb_margin;
|
||||
if (cursor->x >= close_x && cursor->x < close_x + tb_btn_size &&
|
||||
cursor->y >= close_y &&
|
||||
cursor->y < close_y + tb_height - 2 * tb_margin) {
|
||||
pending_kill_client(c);
|
||||
return;
|
||||
}
|
||||
grabc = c;
|
||||
if (grabc->isfloating == 0) {
|
||||
grabc->drag_to_tile = true;
|
||||
exit_scroller_stack(grabc);
|
||||
setfloating(grabc, 1);
|
||||
grabc->drag_tile_float_backup_geom = grabc->float_geom;
|
||||
grabc->old_stack_inner_per = 0.0f;
|
||||
grabc->old_master_inner_per = 0.0f;
|
||||
set_size_per(grabc->mon, grabc);
|
||||
}
|
||||
start_drag_window = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (ji = 0; ji < config.mouse_bindings_count; ji++) {
|
||||
if (config.mouse_bindings_count < 1)
|
||||
break;
|
||||
|
|
@ -2461,6 +2494,10 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
|
|||
}
|
||||
return true;
|
||||
} else {
|
||||
if (start_drag_window && grabc) {
|
||||
grabc = NULL;
|
||||
start_drag_window = false;
|
||||
}
|
||||
cursor_mode = CurNormal;
|
||||
}
|
||||
break;
|
||||
|
|
@ -3800,6 +3837,8 @@ destroynotify(struct wl_listener *listener, void *data) {
|
|||
wl_list_remove(&c->map.link);
|
||||
wl_list_remove(&c->unmap.link);
|
||||
}
|
||||
if (c == hovered_client)
|
||||
hovered_client = NULL;
|
||||
free(c);
|
||||
}
|
||||
|
||||
|
|
@ -4607,6 +4646,18 @@ mapnotify(struct wl_listener *listener, void *data) {
|
|||
wlr_scene_node_lower_to_bottom(&c->shadow->node);
|
||||
wlr_scene_node_set_enabled(&c->shadow->node, true);
|
||||
|
||||
c->titlebar_bg = wlr_scene_rect_create(c->scene, 0, 0, config.title_color);
|
||||
wlr_scene_node_raise_to_top(&c->titlebar_bg->node);
|
||||
wlr_scene_node_set_enabled(&c->titlebar_bg->node, config.enable_titlebars);
|
||||
|
||||
c->titlebar_close =
|
||||
wlr_scene_rect_create(c->scene, 0, 0, config.title_close_color);
|
||||
wlr_scene_node_raise_to_top(&c->titlebar_close->node);
|
||||
wlr_scene_node_set_enabled(&c->titlebar_close->node,
|
||||
config.enable_titlebars);
|
||||
|
||||
wlr_scene_node_raise_to_top(&c->border->node);
|
||||
|
||||
if (config.new_is_master && selmon && !is_scroller_layout(selmon))
|
||||
// tile at the top
|
||||
wl_list_insert(&clients, &c->link); // 新窗口是master,头部入栈
|
||||
|
|
@ -4843,6 +4894,31 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
|
|||
sy = cursor->y - (l ? l->scene->node.y : w->geom.y);
|
||||
}
|
||||
|
||||
/* Update titlebar close button hover */
|
||||
if (hovered_client && hovered_client != c) {
|
||||
update_titlebar_hover(hovered_client);
|
||||
}
|
||||
if (config.enable_titlebars) {
|
||||
hovered_client = c;
|
||||
if (c)
|
||||
update_titlebar_hover(c);
|
||||
}
|
||||
|
||||
/* Initiate titlebar drag on first motion */
|
||||
if (cursor_mode == CurPressed && start_drag_window && grabc) {
|
||||
if (grabc->drag_to_tile && config.drag_tile_small) {
|
||||
grabc->geom.x = cursor->x - 150;
|
||||
grabc->geom.y = cursor->y - 150;
|
||||
grabc->geom.width = 300;
|
||||
grabc->geom.height = 300;
|
||||
resize(grabc, grabc->geom, 1);
|
||||
}
|
||||
grabcx = cursor->x - grabc->geom.x;
|
||||
grabcy = cursor->y - grabc->geom.y;
|
||||
cursor_mode = CurMove;
|
||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab");
|
||||
}
|
||||
|
||||
/* Update drag icon's position */
|
||||
wlr_scene_node_set_position(&drag_icon->node, (int32_t)round(cursor->x),
|
||||
(int32_t)round(cursor->y));
|
||||
|
|
@ -5234,6 +5310,12 @@ void setborder_color(Client *c) {
|
|||
memcpy(c->opacity_animation.target_border_color, border_color,
|
||||
sizeof(c->opacity_animation.target_border_color));
|
||||
client_set_border_color(c, border_color);
|
||||
|
||||
if (c->titlebar_bg) {
|
||||
float *title_color = (c == selmon->sel) ? config.title_color
|
||||
: config.title_unfocused_color;
|
||||
wlr_scene_rect_set_color(c->titlebar_bg, title_color);
|
||||
}
|
||||
}
|
||||
|
||||
void exchange_two_client(Client *c1, Client *c2) {
|
||||
|
|
@ -6488,6 +6570,9 @@ void unmapnotify(struct wl_listener *listener, void *data) {
|
|||
(!c->mon || VISIBLEON(c, c->mon)))
|
||||
init_fadeout_client(c);
|
||||
|
||||
if (c == hovered_client)
|
||||
hovered_client = NULL;
|
||||
|
||||
// If the client is in a stack, remove it from the stack
|
||||
|
||||
if (c->swallowedby) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue