diff --git a/docs/visuals/theming.md b/docs/visuals/theming.md index 2f9993be..75c90f37 100644 --- a/docs/visuals/theming.md +++ b/docs/visuals/theming.md @@ -69,17 +69,17 @@ You can also color-code windows based on their state: ### 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.| +| `group_bar_height` | `50` | Height of the tab bar for monocle layout. | +| `group_bar_decorate_fg_color` | `0xc4939dff` | text color. +| `group_bar_decorate_bg_color` | `0x201b14ff` | background color.| +| `group_bar_decorate_focus_fg_color` | `0x201b14ff` | text color for focus. | +| `group_bar_decorate_focus_bg_color` | `0xc4939dff` | background color for focus.| +| `group_bar_decorate_border_color` | `0x8BAA9Bff` | border color.| +| `group_bar_decorate_border_width` | `4` | border width.| +| `group_bar_decorate_corner_radius` | `5` | corner radius.| +| `group_bar_decorate_padding_x` | `0` | horizontal padding.| +| `group_bar_decorate_padding_y` | `0` | vertical padding.| +| `group_bar_decorate_font_desc` | `monospace Bold 16` | font set.| ## Borders diff --git a/src/action/client.h b/src/action/client.h index 876284cd..aca5d2ef 100644 --- a/src/action/client.h +++ b/src/action/client.h @@ -57,7 +57,18 @@ void client_tile_resize(Client *c, struct wlr_box geo, int32_t interact) { if (!ISFAKETILED(c)) return; - if (!c->isfullscreen && !c->ismaximizescreen) { + if (c->isfullscreen && c->group_bar) { + wlr_scene_node_set_enabled(&c->group_bar->scene_buffer->node, false); + } + + if (!c->mon->isoverview && c->group_bar && !c->isfullscreen && + (c->group_next || c->group_prev)) { + geo.y = geo.y + config.group_bar_height; + geo.height -= config.group_bar_height; + } + + if ((!c->isfullscreen && !c->ismaximizescreen) || + is_scroller_layout(c->mon)) { resize(c, geo, interact); } } @@ -104,19 +115,144 @@ void client_add_jump_label_node(Client *c) { wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node, false); } -void client_add_tab_bar_node(Client *c) { +void client_add_group_bar(Client *c) { - if (config.tab_bar_height <= 0) { + if (config.group_bar_height <= 0) { return; } - MangoNodeData *mangonodedata = ecalloc(1, sizeof(MangoNodeData)); - mangonodedata->node_data = c; - mangonodedata->type = MANGO_TITLE_NODE; + uint32_t layer = c->isoverlay ? LyrOverlay + : c->isfloating || c->isfullscreen ? LyrTop + : c->ismaximizescreen ? LyrMaximize + : LyrTile; - 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); + c->group_bar = mango_group_bar_create(c, GroupBar, layers[layer], + config.tabdata, 0, 0); + wlr_scene_node_lower_to_bottom(&c->group_bar->scene_buffer->node); + wlr_scene_node_set_enabled(&c->group_bar->scene_buffer->node, false); + mango_group_bar_update(c->group_bar, client_get_title(c), 1.0); } + +void client_focus_group_member(Client *c) { + if (!c->group_prev && !c->group_next) + return; + + if (c->isgroupfocusing) + return; + + if (c->mon->isoverview) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur_focusing = NULL; + while (head) { + if (head->isgroupfocusing) { + cur_focusing = head; + break; + } + head = head->group_next; + } + + if (cur_focusing) { + cur_focusing->isgroupfocusing = false; + c->mon = cur_focusing->mon; + client_replace(c, cur_focusing, true); + mango_group_bar_set_focus(cur_focusing->group_bar, false); + } + + c->isgroupfocusing = true; + mango_group_bar_set_focus(c->group_bar, true); + + client_reparent_group(c); + + focusclient(c, 1); + + arrange(c->mon, false, false); +} + +void client_check_tab_node_visible(Client *c) { + + if (!c || c->iskilling) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + if (!c->mon->isoverview && cur->group_bar && + (cur->group_next || cur->group_prev) && VISIBLEON(c, c->mon) && + ISNORMAL(c) && !c->isfullscreen && + (!is_monocle_layout(c->mon) || c == c->mon->sel)) { + wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node, + true); + } else { + wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node, + false); + } + cur = cur->group_next; + } +} + +void client_raise_group(Client *c) { + if (!c || !c->mon) + return; + + if (!c->group_prev && !c->group_next) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + if (cur->group_bar) { + wlr_scene_node_raise_to_top(&cur->group_bar->scene_buffer->node); + wlr_scene_node_raise_to_top(&cur->scene->node); + } + cur = cur->group_next; + } +} + +void client_reparent_group(Client *c) { + if (!c || !c->group_bar) + return; + + if (!c->group_prev && !c->group_next) + return; + + int32_t layer = c->isoverlay ? LyrOverlay + : c->isfloating || c->isfullscreen ? LyrTop + : c->ismaximizescreen ? LyrMaximize + : LyrTile; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + if (cur->group_bar) { + wlr_scene_node_reparent(&cur->group_bar->scene_buffer->node, + layers[layer]); + wlr_scene_node_reparent(&cur->scene->node, layers[layer]); + } + cur = cur->group_next; + } +} + +void client_handle_decorate_click(MangoGroupBar *gb) { + + if (!gb) + return; + + if (gb->node_data) { + Client *c = gb->node_data; + client_focus_group_member(c); + } +} \ No newline at end of file diff --git a/src/animation/client.h b/src/animation/client.h index 832caa0b..39931f0f 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -230,11 +230,13 @@ void scene_buffer_apply_overview_effect(struct wlr_scene_buffer *buffer, bool is_subsurface = false; struct wlr_scene_tree *parent_tree = buffer->node.parent; - if (parent_tree->node.data != NULL) { - SnapshotMetadata *meta = (SnapshotMetadata *)parent_tree->node.data; + SnapshotMetadata *meta = (SnapshotMetadata *)parent_tree->node.data; + if (parent_tree->node.data != NULL && meta->type == Snapshot) { surface_width = meta->orig_width; surface_height = meta->orig_height; is_subsurface = meta->is_subsurface; + } else { + return; } surface_height = surface_height * buffer_data->height_scale; @@ -273,6 +275,86 @@ void buffer_set_effect(Client *c, BufferData data) { } } +void client_draw_title(Client *c) { + + if (!c || !c->group_bar) + return; + + if (!c->group_next && !c->group_prev && c->group_bar && + c->group_bar->scene_buffer->node.enabled) { + wlr_scene_node_set_enabled(&c->group_bar->scene_buffer->node, false); + return; + } + + if (!c->group_next && !c->group_prev) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + int count = 0; + Client *cur = head; + while (cur) { + count++; + cur = cur->group_next; + } + + int32_t tab_x = c->animation.current.x; + int32_t tab_y = c->animation.current.y - config.group_bar_height; + int32_t tw = c->animation.current.width; + int32_t th = config.group_bar_height; + + int32_t left_over = c->mon->m.x - tab_x; + int32_t right_over = tab_x + tw - c->mon->m.x - c->mon->m.width; + int32_t top_over = c->mon->m.y - tab_y; + int32_t bottom_over = + tab_y + config.group_bar_height - c->mon->m.y - c->mon->m.height; + + if (c != grabc && + (ISSCROLLTILED(c) || c->animation.tagining || c->animation.tagouting)) { + if (top_over > 0) { + tab_y = c->mon->m.y; + th = config.group_bar_height - top_over; + } + if (bottom_over > 0) { + th = th - bottom_over; + } + if (right_over > 0) { + tw = tw - right_over; + } + if (left_over > 0) { + tab_x = c->mon->m.x; + tw = tw - left_over; + } + } + + if (tw <= 0 || th <= 0) { + cur = head; + while (cur) { + if (cur->group_bar) + wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node, + false); + cur = cur->group_next; + } + return; + } else { + client_check_tab_node_visible(c); + } + + int32_t bar_w = tw / count; + int32_t rem = tw % count; + int32_t x = tab_x; + cur = head; + + for (int i = 0; i < count && cur; i++) { + int32_t w = bar_w + (i < rem ? 1 : 0); + global_draw_group_bar(cur, x, tab_y, w, th); + x += w; + cur = cur->group_next; + } +} + void apply_shield(Client *c, struct wlr_box clip_box) { if (active_capture_count > 0 && c->shield_when_capture) { wlr_scene_node_raise_to_top(&c->shield->node); @@ -289,18 +371,17 @@ 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) +void global_draw_group_bar(Client *c, int32_t x, int32_t y, int32_t width, + int32_t height) { + if (!c->group_bar) return; if (height <= 0) { - wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, false); + wlr_scene_node_set_enabled(&c->group_bar->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); + wlr_scene_node_set_position(&c->group_bar->scene_buffer->node, x, y); + mango_group_bar_set_size(c->group_bar, width, height); } void apply_split_border(Client *c, bool hit_no_border) { @@ -437,7 +518,8 @@ void apply_border(Client *c) { int32_t right_offset, bottom_offset, left_offset, top_offset; - if (c == grabc) { + if (c == grabc || + (!ISTILED(c) && !c->animation.tagining && !c->animation.tagouting)) { right_offset = 0; bottom_offset = 0; left_offset = 0; @@ -558,10 +640,8 @@ 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) && - (!c->is_monocle_hide || !is_monocle_layout(c->mon))) { + } else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) { c->is_clip_to_hide = false; - c->is_monocle_hide = false; wlr_scene_node_set_enabled(&c->scene->node, true); } @@ -782,6 +862,9 @@ void client_apply_clip(Client *c, float factor) { apply_border(c); + client_draw_title(c); + apply_shield(c, clip_box); + if (clip_box.width <= 0 || clip_box.height <= 0) { return; } @@ -823,6 +906,9 @@ void client_apply_clip(Client *c, float factor) { // 应用窗口装饰 apply_border(c); + client_draw_title(c); + apply_shield(c, clip_box); + // 如果窗口剪切区域已经剪切到0,则不渲染窗口表面 if (clip_box.width <= 0 || clip_box.height <= 0) { should_render_client_surface = false; @@ -999,7 +1085,7 @@ void client_animation_next_tick(Client *c) { c->animation.current = c->geom; } - xytonode(cursor->x, cursor->y, NULL, &pointer_c, NULL, &sx, &sy); + xytonode(cursor->x, cursor->y, NULL, &pointer_c, NULL, NULL, &sx, &sy); surface = pointer_c && pointer_c == c ? client_surface(pointer_c) : NULL; @@ -1274,6 +1360,8 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { apply_border(c); client_get_clip(c, &clip); apply_shield(c, clip); + + client_draw_title(c); wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); return; } diff --git a/src/animation/common.h b/src/animation/common.h index 62a2a494..9e08c770 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -30,7 +30,7 @@ struct dvec2 calculate_animation_curve_at(double t, int32_t type) { void handle_snapshot_meta_destroy(struct wl_listener *listener, void *data) { SnapshotMetadata *meta = wl_container_of(listener, meta, destroy); - wl_list_remove(&meta->destroy.link); // 安全移除监听器 + wl_list_remove(&meta->destroy.link); free(meta); } @@ -164,6 +164,7 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, } meta->orig_width = scene_buffer->dst_width; meta->orig_height = scene_buffer->dst_height; + meta->type = Snapshot; struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer); diff --git a/src/animation/tag.h b/src/animation/tag.h index 859ee1b8..9ff5908f 100644 --- a/src/animation/tag.h +++ b/src/animation/tag.h @@ -45,10 +45,8 @@ void set_tagin_animation(Monitor *m, Client *c) { void set_arrange_visible(Monitor *m, Client *c, bool want_animation) { - if (!ISTILED(c) || ((!c->is_clip_to_hide || !is_scroller_layout(c->mon)) && - (!c->is_monocle_hide || !is_monocle_layout(c->mon)))) { + if (!ISTILED(c) || (!c->is_clip_to_hide || !is_scroller_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); } diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 733990bd..8f953737 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -311,7 +311,7 @@ typedef struct { uint32_t gappoh; uint32_t gappov; uint32_t borderpx; - uint32_t tab_bar_height; + uint32_t group_bar_height; float scratchpad_width_ratio; float scratchpad_height_ratio; float rootcolor[4]; @@ -989,9 +989,17 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, if (strcmp(func_name, "focusstack") == 0) { func = focusstack; (*arg).i = parse_circle_direction(arg_value); + } else if (strcmp(func_name, "groupfocus") == 0) { + func = groupfocus; + (*arg).i = parse_circle_direction(arg_value); } else if (strcmp(func_name, "focusdir") == 0) { func = focusdir; (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "groupjoin") == 0) { + func = groupjoin; + (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "groupleave") == 0) { + func = groupleave; } else if (strcmp(func_name, "focusid") == 0) { func = focusid; } else if (strcmp(func_name, "incnmaster") == 0) { @@ -1708,75 +1716,75 @@ 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) { + } else if (strcmp(key, "group_bar_decorate_font_desc") == 0) { config->tabdata.font_desc = strdup(value); - } else if (strcmp(key, "tab_bar_decorate_fg_color") == 0) { + } else if (strcmp(key, "group_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 " + "group_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) { + } else if (strcmp(key, "group_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 " + "group_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) { + } else if (strcmp(key, "group_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 " + "group_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) { + } else if (strcmp(key, "group_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 " + "group_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) { + } else if (strcmp(key, "group_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 " + "group_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) { + } else if (strcmp(key, "group_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) { + } else if (strcmp(key, "group_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) { + } else if (strcmp(key, "group_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) { + } else if (strcmp(key, "group_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); @@ -1894,8 +1902,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, "group_bar_height") == 0) { + config->group_bar_height = atoi(value); } else if (strcmp(key, "rootcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { @@ -3480,7 +3488,7 @@ 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.group_bar_height = CLAMP_INT(config.group_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 = @@ -3588,7 +3596,7 @@ void set_value_default() { config.idleinhibit_ignore_visible = 0; config.borderpx = 4; - config.tab_bar_height = 50; + config.group_bar_height = 50; config.overviewgappi = 5; config.overviewgappo = 30; config.cursor_hide_timeout = 0; @@ -3956,7 +3964,7 @@ void reapply_property(void) { mango_jump_label_node_apply_config(c->jump_label_node, &config.jumplabeldata); - mango_tab_bar_node_apply_config(c->tab_bar_node, &config.tabdata); + mango_group_bar_apply_config(c->group_bar, &config.tabdata); wlr_scene_rect_set_color(c->droparea, config.dropcolor); wlr_scene_rect_set_color(c->splitindicator[0], config.splitcolor); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 6960b001..056ae82c 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -2,6 +2,8 @@ int32_t minimized(const Arg *arg); int32_t restore_minimized(const Arg *arg); int32_t toggle_scratchpad(const Arg *arg); int32_t focusdir(const Arg *arg); +int32_t groupjoin(const Arg *arg); +int32_t groupleave(const Arg *arg); int32_t toggleoverview(const Arg *arg); int32_t togglejump(const Arg *arg); int32_t set_proportion(const Arg *arg); @@ -38,6 +40,7 @@ int32_t toggleglobal(const Arg *arg); int32_t incnmaster(const Arg *arg); int32_t focusmon(const Arg *arg); int32_t focusstack(const Arg *arg); +int32_t groupfocus(const Arg *arg); int32_t chvt(const Arg *arg); int32_t reload_config(const Arg *arg); int32_t smartmovewin(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index ffcee760..607708a4 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -157,6 +157,86 @@ int32_t focusdir(const Arg *arg) { return 0; } +int32_t groupjoin(const Arg *arg) { + + if (!selmon) + return 0; + + Client *need_join_client = arg->tc ? arg->tc : selmon->sel; + if (!need_join_client) + return 0; + + if (need_join_client->group_next || need_join_client->group_prev) { + return 0; + } + + Client *need_replace_client = NULL; + need_replace_client = direction_select(arg); + + if (!need_replace_client || + need_replace_client->mon != need_join_client->mon) + return 0; + + if (!need_join_client->group_next && !need_join_client->group_prev) { + + if (!need_replace_client->group_prev && + !need_replace_client->group_next) { + need_replace_client->isgroupfocusing = true; + } + + need_join_client->group_next = need_replace_client; + if (need_replace_client->group_prev) { + need_replace_client->group_prev->group_next = need_join_client; + } + need_join_client->group_prev = need_replace_client->group_prev; + need_replace_client->group_prev = need_join_client; + + client_focus_group_member(need_join_client); + arrange(need_join_client->mon, false, false); + return 0; + } + + return 0; +} + +int32_t groupleave(const Arg *arg) { + + if (!selmon) + return 0; + Client *tc = arg->tc ? arg->tc : selmon->sel; + if (!tc || !tc->isgroupfocusing) + return 0; + if (!tc->group_next && !tc->group_prev) { + return 0; + } + Client *rc = tc->group_next ? tc->group_next : tc->group_prev; + + client_focus_group_member(rc); + + if (tc->group_prev) { + tc->group_prev->group_next = tc->group_next; + } + + if (tc->group_next) { + tc->group_next->group_prev = tc->group_prev; + } + + tc->group_prev = NULL; + tc->group_next = NULL; + tc->isgroupfocusing = false; + + wl_list_insert(&rc->link, &tc->link); + wl_list_insert(&rc->flink, &tc->flink); + + if (!rc->group_prev && !rc->group_next) { + rc->isgroupfocusing = false; + } + + arrange(tc->mon, false, false); + + return 0; +} + int32_t focuslast(const Arg *arg) { Client *c = NULL; Client *tc = NULL; @@ -262,6 +342,31 @@ int32_t focusstack(const Arg *arg) { return 0; } +int32_t groupfocus(const Arg *arg) { + Client *c = arg->tc ? arg->tc : selmon->sel; + if (!c) + return 0; + + if (!c->group_prev && !c->group_next) { + return 0; + } + + Client *tc = NULL; + + if (arg->i == NEXT) { + tc = c->group_next; + } else { + tc = c->group_prev; + } + + if (!tc) + return 0; + + client_focus_group_member(tc); + arrange(tc->mon, false, false); + return 0; +} + int32_t incnmaster(const Arg *arg) { if (!arg || !selmon) return 0; @@ -367,7 +472,7 @@ int32_t moveresize(const Arg *arg) { if (cursor_mode != CurNormal && cursor_mode != CurPressed) return 0; - xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL, NULL); if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen || grabc->ismaximizescreen) { grabc = NULL; @@ -1437,6 +1542,8 @@ int32_t toggleoverlay(const Arg *arg) { wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrTop : LyrTile]); } + + client_reparent_group(c); setborder_color(c); return 0; } diff --git a/src/draw/text-node.c b/src/draw/text-node.c index c85b25dc..2b6c21d7 100644 --- a/src/draw/text-node.c +++ b/src/draw/text-node.c @@ -59,10 +59,9 @@ static const struct wlr_buffer_impl text_buffer_impl = { .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)); +MangoJumpLabel *mango_jump_label_node_create(struct wlr_scene_tree *parent, + DecorateDrawData data) { + MangoJumpLabel *node = calloc(1, sizeof(*node)); if (!node) return NULL; @@ -104,7 +103,7 @@ mango_jump_label_node_create(struct wlr_scene_tree *parent, return node; } -void mango_jump_label_node_destroy(struct mango_jump_label_node *node) { +void mango_jump_label_node_destroy(MangoJumpLabel *node) { if (!node) return; @@ -136,8 +135,8 @@ void mango_jump_label_node_destroy(struct mango_jump_label_node *node) { free(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_background(MangoJumpLabel *node, float r, + float g, float b, float a) { if (!node) return; node->bg_color[0] = r; @@ -146,9 +145,9 @@ void mango_jump_label_node_set_background(struct mango_jump_label_node *node, 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) { +void mango_jump_label_node_set_border(MangoJumpLabel *node, float r, float g, + float b, float a, int32_t width, + int32_t radius) { if (!node) return; node->border_color[0] = r; @@ -159,17 +158,16 @@ void mango_jump_label_node_set_border(struct mango_jump_label_node *node, 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) { +void mango_jump_label_node_set_padding(MangoJumpLabel *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) { +static void get_text_pixel_size(MangoJumpLabel *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; @@ -193,8 +191,8 @@ static void draw_rounded_rect(cairo_t *cr, double x, double y, double w, cairo_close_path(cr); } -void mango_jump_label_node_update(struct mango_jump_label_node *node, - const char *text, float scale) { +void mango_jump_label_node_update(MangoJumpLabel *node, const char *text, + float scale) { if (!node || !text) return; if (scale <= 0.0f) @@ -407,8 +405,7 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node, node->logical_height); } -void mango_jump_label_node_set_focus(struct mango_jump_label_node *node, - bool focused) { +void mango_jump_label_node_set_focus(MangoJumpLabel *node, bool focused) { if (!node || node->focused == focused) return; node->focused = focused; @@ -419,55 +416,61 @@ void mango_jump_label_node_set_focus(struct mango_jump_label_node *node, } } -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) +MangoGroupBar *mango_group_bar_create(void *cdata, uint32_t type, + struct wlr_scene_tree *parent, + DecorateDrawData data, int32_t width, + int32_t height) { + MangoGroupBar *mangobar = calloc(1, sizeof(*mangobar)); + if (!mangobar) return NULL; - node->scene_buffer = wlr_scene_buffer_create(parent, NULL); - if (!node->scene_buffer) { - free(node); + mangobar->scene_buffer = wlr_scene_buffer_create(parent, NULL); + if (!mangobar->scene_buffer) { + free(mangobar); 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 = + memcpy(mangobar->fg_color, data.fg_color, sizeof(mangobar->fg_color)); + memcpy(mangobar->bg_color, data.bg_color, sizeof(mangobar->bg_color)); + memcpy(mangobar->focus_fg_color, data.focus_fg_color, + sizeof(mangobar->focus_fg_color)); + memcpy(mangobar->focus_bg_color, data.focus_bg_color, + sizeof(mangobar->focus_bg_color)); + memcpy(mangobar->border_color, data.border_color, + sizeof(mangobar->border_color)); + mangobar->border_width = data.border_width; + mangobar->corner_radius = data.corner_radius; + mangobar->padding_x = data.padding_x; + mangobar->padding_y = data.padding_y; + mangobar->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; + mangobar->target_width = width; + mangobar->target_height = height; + mangobar->focused = false; + mangobar->cached_focused = false; - node->measure_surface = + mangobar->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; + mangobar->measure_cr = cairo_create(mangobar->measure_surface); + mangobar->measure_context = + pango_cairo_create_context(mangobar->measure_cr); + mangobar->measure_layout = pango_layout_new(mangobar->measure_context); + mangobar->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; + mangobar->cached_scale = -1.0f; + mangobar->last_text = NULL; + mangobar->last_scale = 0.0f; - return node; + mangobar->type = type; + mangobar->node_data = cdata; + + mangobar->scene_buffer->node.data = mangobar; + + return mangobar; } -void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node) { +void mango_group_bar_destroy(MangoGroupBar *node) { if (!node) return; @@ -492,19 +495,15 @@ void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node) { 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) { +void mango_group_bar_set_size(MangoGroupBar *node, int32_t width, + int32_t height) { if (!node) return; @@ -522,11 +521,11 @@ void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width, 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); + mango_group_bar_update(node, redraw_text, redraw_scale); } -void mango_tab_bar_node_update(struct mango_tab_bar_node *node, - const char *text, float scale) { +void mango_group_bar_update(MangoGroupBar *node, const char *text, + float scale) { if (!node || !text) return; if (scale <= 0.0f) @@ -765,19 +764,18 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, node->logical_height); } -void mango_tab_bar_node_set_focus(struct mango_tab_bar_node *node, - bool focused) { +void mango_group_bar_set_focus(MangoGroupBar *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); + mango_group_bar_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]) { +void mango_group_bar_set_colors(MangoGroupBar *node, const float fg[4], + const float bg[4]) { if (!node) return; @@ -786,11 +784,11 @@ void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node, 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); + mango_group_bar_update(node, node->last_text, scale); } } -void mango_jump_label_node_apply_config(struct mango_jump_label_node *node, +void mango_jump_label_node_apply_config(MangoJumpLabel *node, const DecorateDrawData *data) { if (!node || !data) return; @@ -817,8 +815,8 @@ void mango_jump_label_node_apply_config(struct mango_jump_label_node *node, } } -void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node, - const DecorateDrawData *data) { +void mango_group_bar_apply_config(MangoGroupBar *node, + const DecorateDrawData *data) { if (!node || !data) return; @@ -840,6 +838,6 @@ void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node, 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); + mango_group_bar_update(node, node->last_text, scale); } } \ No newline at end of file diff --git a/src/draw/text-node.h b/src/draw/text-node.h index 079af908..23ac4f9a 100644 --- a/src/draw/text-node.h +++ b/src/draw/text-node.h @@ -26,8 +26,7 @@ struct mango_text_buffer { struct wlr_buffer base; cairo_surface_t *surface; }; - -struct mango_jump_label_node { +typedef struct { struct wlr_scene_buffer *scene_buffer; struct mango_text_buffer *buffer; cairo_surface_t *surface; @@ -70,13 +69,15 @@ struct mango_jump_label_node { int32_t logical_width; int32_t logical_height; -}; +} MangoJumpLabel; -struct mango_tab_bar_node { +typedef struct { + uint32_t type; // must at first in struct struct wlr_scene_buffer *scene_buffer; struct mango_text_buffer *buffer; cairo_surface_t *surface; int surface_pixel_w, surface_pixel_h; + void *node_data; // 存储窗口指针 // 初始配置 float fg_color[4]; @@ -126,41 +127,38 @@ struct mango_tab_bar_node { int32_t logical_width; int32_t logical_height; -}; +} MangoGroupBar; 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); +MangoJumpLabel *mango_jump_label_node_create(struct wlr_scene_tree *parent, + DecorateDrawData data); +void mango_jump_label_node_destroy(MangoJumpLabel *node); +void mango_jump_label_node_set_background(MangoJumpLabel *node, float r, + float g, float b, float a); +void mango_jump_label_node_set_border(MangoJumpLabel *node, float r, float g, + float b, float a, int32_t width, + int32_t radius); +void mango_jump_label_node_set_padding(MangoJumpLabel *node, int32_t pad_x, + int32_t pad_y); +void mango_jump_label_node_update(MangoJumpLabel *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); +MangoGroupBar *mango_group_bar_create(void *cdata, uint32_t type, + struct wlr_scene_tree *parent, + DecorateDrawData data, int32_t width, + int32_t height); +void mango_group_bar_destroy(MangoGroupBar *node); +void mango_group_bar_set_size(MangoGroupBar *node, int32_t width, + int32_t height); +void mango_group_bar_update(MangoGroupBar *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_jump_label_node_set_focus(MangoJumpLabel *node, bool focused); +void mango_group_bar_set_focus(MangoGroupBar *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, +void mango_group_bar_set_colors(MangoGroupBar *node, const float fg[4], + const float bg[4]); +void mango_jump_label_node_apply_config(MangoJumpLabel *node, const DecorateDrawData *data); -void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node, - const DecorateDrawData *data); +void mango_group_bar_apply_config(MangoGroupBar *node, + const DecorateDrawData *data); #endif // jump_label_node_H \ No newline at end of file diff --git a/src/ext-protocol/tablet.h b/src/ext-protocol/tablet.h index 34c82dbf..afa0ebc1 100644 --- a/src/ext-protocol/tablet.h +++ b/src/ext-protocol/tablet.h @@ -281,7 +281,7 @@ void tablettoolmotion(struct TabletTool *tool, bool change_x, bool change_y, if (config.sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + xytonode(cursor->x, cursor->y, &surface, &c, NULL, NULL, &sx, &sy); if (cursor_mode == CurPressed && !seat->drag && surface != seat->pointer_state.focused_surface && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index 7b4e1a1f..0eb89881 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -27,6 +27,7 @@ struct dwl_input_method_relay { }; struct dwl_input_method_popup { + uint32_t type; // must at first in struct struct wlr_input_popup_surface_v2 *popup_surface; struct wlr_scene_tree *tree; struct wlr_scene_tree *scene_surface; @@ -404,6 +405,8 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener, popup->tree = wlr_scene_tree_create(layers[LyrIMPopup]); popup->scene_surface = wlr_scene_subsurface_tree_create( popup->tree, popup->popup_surface->surface); + + popup->type = XdgImPopup; popup->scene_surface->node.data = popup; wl_list_insert(&relay->popups, &popup->link); diff --git a/src/fetch/client.h b/src/fetch/client.h index a44f4ca7..e7d8e673 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -188,8 +188,6 @@ 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 (!config.focus_cross_monitor && c->mon != tc->mon) @@ -197,11 +195,6 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, if (!(c->tags & c->mon->tagset[c->mon->seltags])) continue; - if (step == 0 && ((!tc->mon->isoverview && - !client_is_in_same_stack(tc, c, NULL)) || - c->mon != tc->mon)) - continue; - int32_t c_l = c->geom.x; int32_t c_r = c->geom.x + c->geom.width; int32_t c_t = c->geom.y; @@ -257,17 +250,24 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, if (!match_dir) continue; + if (step == 0) { + if (c->mon != tc->mon) + continue; + if (!tc->mon->isoverview && + !client_is_in_same_stack(tc, c, NULL)) + continue; + if (orth_dist != 0) + continue; + } + int64_t penalty = 0; if (main_dist < 0) { - penalty = 10000000000LL; // 主方向重叠(反方向)的极大惩罚 + penalty = 10000000000LL; main_dist = -main_dist; } - // 正交方向无重叠惩罚,优先选择在同一行/列的窗口 int64_t no_overlap_penalty = 0; if (orth_dist > 0) { - // LEFT/RIGHT 时 orth_dist 是垂直间距,>0 表示垂直无重叠 - // UP/DOWN 时 orth_dist 是水平间距,>0 表示水平无重叠 no_overlap_penalty = 10000000LL; } @@ -442,7 +442,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 || tc->is_monocle_hide) + if (tc->iskilling || tc->isunglobal) continue; if (!VISIBLEON(tc, sc->mon)) continue; diff --git a/src/fetch/common.h b/src/fetch/common.h index acb5d0e8..d017dff3 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -100,23 +100,30 @@ static bool layer_ignores_focus(LayerSurface *l) { } void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, - LayerSurface **pl, double *nx, double *ny) { - struct wlr_scene_node *node, *pnode; + LayerSurface **pl, MangoGroupBar **gb, double *nx, double *ny) { + struct wlr_scene_node *node = NULL, *pnode = NULL; struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; + MangoGroupBar *mangogroupbar = NULL; int32_t layer; Client *ovc = NULL; - for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { + if (psurface) + *psurface = NULL; + if (pc) + *pc = NULL; + if (pl) + *pl = NULL; + if (gb) + *gb = NULL; + for (layer = NUM_LAYERS - 1; layer >= 0; layer--) { if (layer == LyrFadeOut) continue; - if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) - continue; - - if (!node->enabled) + node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny); + if (!node) continue; if (node->type == WLR_SCENE_NODE_BUFFER) { @@ -125,23 +132,30 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, wlr_scene_buffer_from_node(node)); if (scene_surface) { surface = scene_surface->surface; - } else { - continue; } } - /* start from the topmost layer, - find a sureface that can be focused by pointer, - impopup neither a client nor a layer surface.*/ if (layer == LyrIMPopup) { c = NULL; l = NULL; } else { - for (pnode = node; pnode && !c; pnode = &pnode->parent->node) - c = pnode->data; - if (c && c->type == LayerShell) { - l = (LayerSurface *)c; - c = NULL; + void *data = NULL; + for (pnode = node; pnode; pnode = &pnode->parent->node) { + if (pnode->data) { + data = pnode->data; + break; + } + } + + if (data) { + Client *temp_c = (Client *)data; + if (temp_c->type == LayerShell) { + l = (LayerSurface *)temp_c; + } else if (temp_c->type == GroupBar) { + mangogroupbar = (MangoGroupBar *)temp_c; + } else if (temp_c->type == XDGShell || temp_c->type == X11) { + c = temp_c; + } } } @@ -149,8 +163,9 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, if (c) { surface = client_surface(c); } - break; } + + break; } if (psurface) @@ -159,6 +174,8 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, *pc = c; if (pl) *pl = l; + if (gb) + *gb = mangogroupbar; if (selmon && selmon->isoverview && config.ov_no_resize) { ovc = xytoclient(x, y); @@ -174,12 +191,12 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, if (ovc && (!l || layer_ignores_focus(l) || is_below)) { if (pc) *pc = ovc; - if (psurface) *psurface = ovc ? client_surface(ovc) : NULL; - - if (pl && ovc) + if (pl) *pl = NULL; + if (gb) + *gb = NULL; } } } \ No newline at end of file diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 4782b3ea..803970da 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -20,7 +20,7 @@ void set_size_per(Monitor *m, Client *c) { } } - if (!found) { + if (!found || c->isfloating) { c->master_mfact_per = m->pertag->mfacts[m->pertag->curtag]; c->master_inner_per = 1.0f; c->stack_inner_per = 1.0f; @@ -37,21 +37,6 @@ 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) { @@ -1147,14 +1132,8 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation, 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->group_bar && c->group_bar->scene_buffer->node.enabled) { + client_check_tab_node_visible(c); } if (c->mon == m && (c->isglobal || c->isunglobal)) { diff --git a/src/layout/dwindle.h b/src/layout/dwindle.h index 5e56a6bf..e291c69b 100644 --- a/src/layout/dwindle.h +++ b/src/layout/dwindle.h @@ -261,7 +261,7 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay, !node->client->ismaximizescreen) { struct wlr_box box = {ax, ay, MANGO_MAX(1, aw), MANGO_MAX(1, ah)}; - resize(node->client, box, 0); + client_tile_resize(node->client, box, 0); } } return; diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 96c0ed54..8788c210 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -545,83 +545,32 @@ void deck(Monitor *m) { } } -void monocle(Monitor *m) { - Client *c = NULL, *fc = NULL; +void // 17 +monocle(Monitor *m) { + Client *c = 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; - if (config.smartgaps && m->visible_fake_tiling_clients == 1) { - cur_gappov = cur_gappoh = cur_gapiv = cur_gapih = 0; - } - - 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(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; + 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; 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.y = m->w.y + cur_gappov; geom.width = m->w.width - 2 * cur_gappoh; - geom.height = main_height; + geom.height = m->w.height - 2 * cur_gappov; 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); } // 网格布局窗口大小和位置计算 diff --git a/src/layout/overview.h b/src/layout/overview.h index 1ae9e7a0..80b2e31d 100644 --- a/src/layout/overview.h +++ b/src/layout/overview.h @@ -1,4 +1,3 @@ - typedef struct { float x, y, w, h; } OvPlacedRect; @@ -232,16 +231,20 @@ void overview_scale(Monitor *m) { float base_x = m->w.x + target_gappo + dx; float base_y = m->w.y + target_gappo + dy; + // 收集所有客户端的目标几何,最后统一调用 client_tile_resize + struct wlr_box overview_boxes[n]; // C99 VLA,n > 0 时有效 for (int k = 0; k < n; k++) { - Client *cl = items[k].c; - struct wlr_box geom; - geom.x = (int)(base_x + placed[k].x + 0.5f); - geom.y = (int)(base_y + placed[k].y + 0.5f); float w = items[k].orig_w * best_s; float h = items[k].orig_h * best_s; - geom.width = (int)(geom.x + w + 0.5f) - geom.x; - geom.height = (int)(geom.y + h + 0.5f) - geom.y; - resize(cl, geom, 0); + int ix = (int)(base_x + placed[k].x + 0.5f); + int iy = (int)(base_y + placed[k].y + 0.5f); + int iw = (int)(ix + w + 0.5f) - ix; + int ih = (int)(iy + h + 0.5f) - iy; + overview_boxes[k] = (struct wlr_box){ix, iy, iw, ih}; + } + + for (int k = 0; k < n; k++) { + client_tile_resize(items[k].c, overview_boxes[k], 0); } } @@ -280,74 +283,69 @@ void overview_resize(Monitor *m) { return; } + // 临时存储每个客户端的目标几何 + struct wlr_box boxes[n]; // C99 VLA + if (n == 1) { int32_t cw = (m->w.width - 2 * target_gappo) * single_width_ratio; int32_t ch = (m->w.height - 2 * target_gappo) * single_height_ratio; - c_arr[0]->geom.x = m->w.x + (m->w.width - cw) / 2; - c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2; - c_arr[0]->geom.width = cw; - c_arr[0]->geom.height = ch; - resize(c_arr[0], c_arr[0]->geom, 0); - free(c_arr); - return; - } - - if (n == 2) { + boxes[0].x = m->w.x + (m->w.width - cw) / 2; + boxes[0].y = m->w.y + (m->w.height - ch) / 2; + boxes[0].width = cw; + boxes[0].height = ch; + } else if (n == 2) { int32_t cw = (m->w.width - 2 * target_gappo - target_gappi) / 2; int32_t ch = (m->w.height - 2 * target_gappo) * 0.65f; - c_arr[0]->geom.x = m->w.x + target_gappo; - c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo; - c_arr[0]->geom.width = cw; - c_arr[0]->geom.height = ch; - resize(c_arr[0], c_arr[0]->geom, 0); + boxes[0].x = m->w.x + target_gappo; + boxes[0].y = m->w.y + (m->w.height - ch) / 2 + target_gappo; + boxes[0].width = cw; + boxes[0].height = ch; - c_arr[1]->geom.x = m->w.x + cw + target_gappo + target_gappi; - c_arr[1]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo; - c_arr[1]->geom.width = cw; - c_arr[1]->geom.height = ch; - resize(c_arr[1], c_arr[1]->geom, 0); + boxes[1].x = m->w.x + cw + target_gappo + target_gappi; + boxes[1].y = m->w.y + (m->w.height - ch) / 2 + target_gappo; + boxes[1].width = cw; + boxes[1].height = ch; + } else { + int32_t cols = 1; + while (cols * cols < n) + cols++; + int32_t rows = (n + cols - 1) / cols; - free(c_arr); - return; - } + int32_t ch = + (m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows; + int32_t cw = + (m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols; - int32_t cols = 1; - while (cols * cols < n) { - cols++; - } - int32_t rows = (n + cols - 1) / cols; + if (ch < 1) + ch = 1; + if (cw < 1) + cw = 1; - int32_t ch = - (m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows; - int32_t cw = - (m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols; - - if (ch < 1) - ch = 1; - if (cw < 1) - cw = 1; - - int32_t overcols = n % cols; - int32_t dx = 0; - if (overcols) { - dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) / 2 - - target_gappo; - } - - for (int i = 0; i < n; i++) { - int32_t cx = m->w.x + (i % cols) * (cw + target_gappi); - int32_t cy = m->w.y + (i / cols) * (ch + target_gappi); - - if (overcols && i >= n - overcols) { - cx += dx; + int32_t overcols = n % cols; + int32_t dx = 0; + if (overcols) { + dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) / + 2 - + target_gappo; } - c_arr[i]->geom.x = cx + target_gappo; - c_arr[i]->geom.y = cy + target_gappo; - c_arr[i]->geom.width = cw; - c_arr[i]->geom.height = ch; - resize(c_arr[i], c_arr[i]->geom, 0); + for (int i = 0; i < n; i++) { + int32_t cx = m->w.x + (i % cols) * (cw + target_gappi); + int32_t cy = m->w.y + (i / cols) * (ch + target_gappi); + if (overcols && i >= n - overcols) + cx += dx; + + boxes[i].x = cx + target_gappo; + boxes[i].y = cy + target_gappo; + boxes[i].width = cw; + boxes[i].height = ch; + } + } + + // 统一应用所有几何变更,使用 client_tile_resize + for (int k = 0; k < n; k++) { + client_tile_resize(c_arr[k], boxes[k], 0); } free(c_arr); @@ -365,9 +363,7 @@ void create_jump_hints(Monitor *m) { 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); @@ -385,12 +381,10 @@ void create_jump_hints(Monitor *m) { 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) { + if (!m->is_jump_mode) return; - } + Client *c; wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m)) { if (c->jump_label_node->scene_buffer->node.enabled) { @@ -400,12 +394,10 @@ void finish_jump_mode(Monitor *m) { } } } - m->is_jump_mode = 0; } void overview(Monitor *m) { - if (config.ov_no_resize) { overview_scale(m); } else { @@ -415,4 +407,4 @@ void overview(Monitor *m) { if (m->is_jump_mode) { create_jump_hints(m); } -} \ No newline at end of file +} diff --git a/src/layout/scroll.h b/src/layout/scroll.h index b800c5cf..dbdfe919 100644 --- a/src/layout/scroll.h +++ b/src/layout/scroll.h @@ -36,7 +36,6 @@ scroller_node_create(struct TagScrollerState *st, Client *c) { return n; } -/* 从 tag 状态中移除一个节点并释放 */ static void scroller_node_remove(struct TagScrollerState *st, struct ScrollerStackNode *target) { if (!st || !target) @@ -223,7 +222,7 @@ void arrange_stack_node(struct ScrollerStackNode *head, struct wlr_box geometry, .y = current_y, .width = geometry.width, .height = client_height}; - resize(iter->client, client_geom, 0); + client_tile_resize(iter->client, client_geom, 0); remain_proportion -= iter->stack_proportion; remain_client_height -= client_height; current_y += client_height + gappiv; @@ -272,7 +271,7 @@ void arrange_stack_vertical_node(struct ScrollerStackNode *head, .x = current_x, .height = geometry.height, .width = client_width}; - resize(iter->client, client_geom, 0); + client_tile_resize(iter->client, client_geom, 0); remain_proportion -= iter->stack_proportion; remain_client_width -= client_width; current_x += client_width + gappih; @@ -508,6 +507,7 @@ void scroller(Monitor *m) { void vertical_scroller(Monitor *m) { uint32_t tag = m->pertag->curtag; + int32_t bar_height = 0; struct TagScrollerState *st = ensure_scroller_state(m, tag); Client *c = NULL; float scroller_default_proportion_single = @@ -696,7 +696,12 @@ void vertical_scroller(Monitor *m) { arrange_stack_vertical_node(heads[focus_index], target_geom, cur_gappih); } else { - target_geom.y = root_client->geom.y; + bar_height = !root_client->isfullscreen && (root_client->group_prev || + root_client->group_next) + ? config.group_bar_height + : 0; + + target_geom.y = root_client->geom.y - bar_height; vertical_check_scroller_root_inside_mon(heads[focus_index]->client, &target_geom); arrange_stack_vertical_node(heads[focus_index], target_geom, @@ -709,8 +714,15 @@ void vertical_scroller(Monitor *m) { up_geom.width = m->w.width - 2 * cur_gappoh; up_geom.height = max_client_height * cur->scroller_proportion; vertical_scroll_adjust_fullandmax(cur->client, &up_geom); + + bar_height = !heads[focus_index - i + 1]->client->isfullscreen && + (heads[focus_index - i + 1]->client->group_prev || + heads[focus_index - i + 1]->client->group_next) + ? config.group_bar_height + : 0; + up_geom.y = heads[focus_index - i + 1]->client->geom.y - cur_gappiv - - up_geom.height; + up_geom.height - bar_height; arrange_stack_vertical_node(cur, up_geom, cur_gappih); } @@ -902,7 +914,6 @@ static void update_scroller_state(Monitor *m) { break; } - /* 移除不再可见的节点 */ struct ScrollerStackNode *n = st->all_first; while (n) { bool found = false; diff --git a/src/mango.c b/src/mango.c index 63402c11..90e3ca66 100644 --- a/src/mango.c +++ b/src/mango.c @@ -112,6 +112,8 @@ #define ISTILED(A) \ (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) +#define ISNORMAL(A) \ + (A && !(A)->isminimized && !(A)->iskilling && !(A)->isunglobal) #define ISSCROLLTILED(A) \ (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->isunglobal) @@ -161,13 +163,21 @@ enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; enum { VERTICAL, HORIZONTAL }; enum { SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT }; enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ -enum { XDGShell, LayerShell, X11 }; /* client types */ -enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向 +enum { + XDGShell, + LayerShell, + X11, + Snapshot, + XdgPopup, + XdgImPopup, + GroupBar +}; /* client types */ +enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向 enum { LyrBg, LyrBottom, - LyrDecorate, LyrTile, + LyrMaximize, LyrTop, LyrFadeOut, LyrOverlay, @@ -176,8 +186,6 @@ enum { NUM_LAYERS }; /* scene layers */ -enum mango_node_type { MANGO_TITLE_NODE, MANGO_jump_label_node }; - #ifdef XWAYLAND enum { NetWMWindowTypeDialog, @@ -243,12 +251,6 @@ typedef struct { uint32_t ui2; Client *tc; } Arg; - -typedef struct { - enum mango_node_type type; - void *node_data; -} MangoNodeData; - typedef struct { uint32_t mod; uint32_t button; @@ -321,7 +323,7 @@ typedef struct { struct Client { /* Must keep these three elements in this order */ - uint32_t type; /* XDGShell or X11* */ + uint32_t type; // must at first in struct struct wlr_box geom, pending, float_geom, animainit_geom, overview_backup_geom, current, drag_begin_geom; /* layout-relative, includes border */ @@ -339,8 +341,9 @@ 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; + MangoJumpLabel *jump_label_node; + MangoGroupBar *group_bar; + struct wl_list link; struct wl_list flink; struct wl_list fadeout_link; @@ -407,7 +410,6 @@ 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; @@ -458,6 +460,9 @@ struct Client { int32_t grid_col_idx; int32_t grid_row_idx; uint32_t id; + Client *group_prev; + Client *group_next; + bool isgroupfocusing; }; typedef struct { @@ -497,7 +502,7 @@ typedef struct { typedef struct { /* Must keep these three elements in this order */ - uint32_t type; /* LayerShell */ + uint32_t type; // must at first in struct struct wlr_box geom, current, pending, animainit_geom; Monitor *mon; struct wlr_scene_tree *scene; @@ -523,6 +528,7 @@ typedef struct { } LayerSurface; typedef struct { + uint32_t type; // must at first in struct struct wlr_xdg_popup *wlr_popup; struct wl_listener destroy; struct wl_listener commit; @@ -642,6 +648,7 @@ struct TagScrollerState { }; typedef struct { + uint32_t type; // must at first in struct int32_t orig_width; int32_t orig_height; bool is_subsurface; @@ -792,12 +799,13 @@ static void virtualpointer(struct wl_listener *listener, void *data); static void warp_cursor(const Client *c); static Monitor *xytomon(double x, double y); static void xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny); + Client **pc, LayerSurface **pl, MangoGroupBar **tb, + double *nx, double *ny); static void clear_fullscreen_flag(Client *c); static pid_t getparentprocess(pid_t p); static int32_t isdescprocess(pid_t p, pid_t c); static Client *termforwin(Client *w); -static void swallow(Client *c, Client *w); +static void client_replace(Client *c, Client *w, bool isgroupaction); static void warp_cursor_to_selmon(Monitor *m); uint32_t want_restore_fullscreen(Client *target_client); @@ -930,6 +938,10 @@ 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); +static void global_draw_group_bar(Client *c, int32_t x, int32_t y, + int32_t width, int32_t height); + +static void client_reparent_group(Client *c); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -1266,7 +1278,7 @@ void client_update_oldmonname_record(Client *c, Monitor *m) { c->oldmonname[sizeof(c->oldmonname) - 1] = '\0'; } -void swallow(Client *c, Client *w) { +void client_replace(Client *c, Client *w, bool isgroupaction) { c->bw = w->bw; c->isfloating = w->isfloating; c->isurgent = w->isurgent; @@ -1281,10 +1293,43 @@ void swallow(Client *c, Client *w) { c->scroller_proportion = w->scroller_proportion; c->isglobal = w->isglobal; c->overview_backup_geom = w->overview_backup_geom; - - /* 调整 w 的邻居指针,让它们指向 c */ + c->animation.current = w->animation.current; c->stack_proportion = w->stack_proportion; + if (!isgroupaction) { + + if (w->group_prev == c) { + c->group_next = w->group_next; + if (w->group_next) { + w->group_next->group_prev = c; + } + } else if (w->group_next == c) { + c->group_prev = w->group_prev; + if (w->group_prev) { + w->group_prev->group_next = c; + } + } else { + c->group_prev = w->group_prev; + c->group_next = w->group_next; + if (w->group_prev) { + w->group_prev->group_next = c; + } + + if (w->group_next) { + w->group_next->group_prev = c; + } + } + + if (!c->group_prev && !c->group_next) { + c->isgroupfocusing = false; + } else { + c->isgroupfocusing = w->isgroupfocusing; + } + + if (c->isgroupfocusing) + mango_group_bar_set_focus(c->group_bar, true); + } + if (w->overview_scene_surface) { wlr_scene_node_destroy(&w->scene_surface->node); w->scene_surface = w->overview_scene_surface; @@ -1295,13 +1340,36 @@ 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); + if (w->group_bar && !isgroupaction) { + wlr_scene_node_set_enabled(&w->group_bar->scene_buffer->node, false); } - /* 全局链表替换 */ - wl_list_insert(&w->link, &c->link); - wl_list_insert(&w->flink, &c->flink); + if (c->link.prev && c->link.next && c->link.prev != &c->link) { + wl_list_remove(&c->link); + } + wl_list_init(&c->link); + + if (c->flink.prev && c->flink.next && c->flink.prev != &c->flink) { + wl_list_remove(&c->flink); + } + wl_list_init(&c->flink); + + if (w->link.prev && w->link.next && w->link.prev != &w->link) { + wl_list_insert(w->link.prev, &c->link); + wl_list_remove(&w->link); + wl_list_init(&w->link); + } + + if (w->flink.prev && w->flink.next && w->flink.prev != &w->flink) { + if (selmon && c == selmon->sel) { + wl_list_insert(&fstack, &c->flink); + } else { + wl_list_insert(w->flink.prev, &c->flink); + } + wl_list_remove(&w->flink); + wl_list_init(&w->flink); + } + /* --------------------------------------------------------------------- */ if (w->foreign_toplevel) { wlr_foreign_toplevel_handle_v1_output_leave(w->foreign_toplevel, @@ -1350,12 +1418,10 @@ void swallow(Client *c, Client *w) { struct TagScrollerState *st = w->mon->pertag->scroller_state[t]; if (!st) continue; - /* 先移除 c 在任意 tag 中的旧节点 */ struct ScrollerStackNode *cn = find_scroller_node(st, c); if (cn) scroller_node_remove(st, cn); - /* 将 w 的节点(如果存在)转给 c */ struct ScrollerStackNode *wn = find_scroller_node(st, w); if (wn) wn->client = c; @@ -1770,11 +1836,9 @@ void applyrules(Client *c) { if (p && !p->isminimized) { c->swallowedby = p; p->swallowing = c; - wl_list_remove(&c->link); - wl_list_remove(&c->flink); - swallow(c, p); - wl_list_remove(&p->link); - wl_list_remove(&p->flink); + + client_replace(c, p, false); + mon = p->mon; newtags = p->tags; } @@ -1789,7 +1853,10 @@ void applyrules(Client *c) { (!c->istagsilent || !newtags || newtags & mon->tagset[mon->seltags]); if (!should_init_get_focus) { - wl_list_remove(&c->flink); + if (c->flink.prev && c->flink.next && c->flink.prev != &c->flink) { + wl_list_remove(&c->flink); + wl_list_init(&c->flink); + } wl_list_insert(fstack.prev, &c->flink); } @@ -1826,7 +1893,10 @@ void applyrules(Client *c) { } if (c->isfloating && !c->iscustompos && !c->isnamedscratchpad) { - wl_list_remove(&c->link); + if (c->link.prev && c->link.next && c->link.prev != &c->link) { + wl_list_remove(&c->link); + wl_list_init(&c->link); + } wl_list_insert(clients.prev, &c->link); set_float_malposition(c); } @@ -2357,6 +2427,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) { uint32_t hard_mods, mods; Client *c = NULL; LayerSurface *l = NULL; + MangoGroupBar *gb = NULL; struct wlr_surface *surface; Client *tmpc = NULL; int32_t ji; @@ -2378,7 +2449,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) { if (locked) break; - xytonode(cursor->x, cursor->y, &surface, NULL, NULL, NULL, NULL); + xytonode(cursor->x, cursor->y, &surface, NULL, NULL, &gb, NULL, NULL); if (toplevel_from_wlr_surface(surface, &c, &l) >= 0) { if (c && c->scene->node.enabled && (!client_is_unmanaged(c) || client_wants_focus(c))) @@ -2409,15 +2480,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) { } // 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); - } - } + client_handle_decorate_click(gb); // 当鼠标焦点在layer上的时候,不检测虚拟键盘的mod状态, // 避免layer虚拟键盘锁死mod按键状态 @@ -2582,6 +2645,7 @@ void cleanuplisteners(void) { wl_list_remove(&new_foreign_toplevel_capture_request.link); wl_list_remove(&tearing_new_object.link); wl_list_remove(&keyboard_shortcuts_inhibit_new_inhibitor.link); + wl_list_remove(&ext_image_copy_capture_mgr_new_session.link); if (drm_lease_manager) { wl_list_remove(&drm_lease_request.link); } @@ -3011,6 +3075,8 @@ static void createpopup(struct wl_listener *listener, void *data) { if (!popup) return; + popup->type = XdgPopup; + popup->destroy.notify = destroypopup; wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); @@ -3435,30 +3501,22 @@ void destroyinputdevice(struct wl_listener *listener, void *data) { InputDevice *input_dev = wl_container_of(listener, input_dev, destroy_listener); - // 清理设备特定数据 if (input_dev->device_data) { - // 根据设备类型进行特定清理 switch (input_dev->wlr_device->type) { case WLR_INPUT_DEVICE_SWITCH: { Switch *sw = (Switch *)input_dev->device_data; - // 移除 toggle 监听器 wl_list_remove(&sw->toggle.link); - // 释放 Switch 内存 free(sw); break; } - // 可以添加其他设备类型的清理代码 default: break; } input_dev->device_data = NULL; } - // 从设备列表中移除 wl_list_remove(&input_dev->link); - // 移除 destroy 监听器 wl_list_remove(&input_dev->destroy_listener.link); - // 释放内存 free(input_dev); } @@ -3808,8 +3866,10 @@ void focusclient(Client *c, int32_t lift) { return; /* Raise client in stacking order if requested */ - if (c && lift) + if (c && lift) { + client_raise_group(c); wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 + } if (c && client_surface(c) == old_keyboard_focus_surface && selmon && selmon->sel) @@ -4348,11 +4408,13 @@ void locksession(struct wl_listener *listener, void *data) { } void init_client_properties(Client *c) { + c->isgroupfocusing = false; + c->group_prev = NULL; + c->group_next = NULL; 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->group_bar = NULL; c->overview_scene_surface = NULL; c->drop_direction = UNDIR; c->enable_drop_area_draw = false; @@ -4534,6 +4596,8 @@ mapnotify(struct wl_listener *listener, void *data) { wlr_scene_node_set_enabled(&c->splitindicator[i]->node, false); } + client_add_group_bar(c); + c->droparea = wlr_scene_rect_create(c->scene, 0, 0, config.dropcolor); wlr_scene_node_lower_to_bottom(&c->droparea->node); wlr_scene_node_set_position(&c->droparea->node, 0, 0); @@ -4766,7 +4830,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, } /* Find the client under the pointer and send the event along. */ - xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + xytonode(cursor->x, cursor->y, &surface, &c, NULL, NULL, &sx, &sy); if (cursor_mode == CurPressed && !seat->drag && surface != seat->pointer_state.focused_surface && @@ -5492,6 +5556,12 @@ setfloating(Client *c, int32_t floating) { layers[c->isfloating ? LyrTop : LyrTile]); } + client_reparent_group(c); + + if (c->isfloating) { + set_size_per(c->mon, c); + } + if (!c->force_fakemaximize) client_set_maximized(c, false); @@ -5514,11 +5584,18 @@ setfloating(Client *c, int32_t floating) { } void reset_maximizescreen_size(Client *c) { - c->geom.x = c->mon->w.x + config.gappoh; - c->geom.y = c->mon->w.y + config.gappov; - c->geom.width = c->mon->w.width - 2 * config.gappoh; - c->geom.height = c->mon->w.height - 2 * config.gappov; - resize(c, c->geom, 0); + struct wlr_box geom; + geom.x = c->mon->w.x + config.gappoh; + geom.y = c->mon->w.y + config.gappov; + geom.width = c->mon->w.width - 2 * config.gappoh; + geom.height = c->mon->w.height - 2 * config.gappov; + + if ((c->group_next || c->group_prev) && c->group_bar) { + geom.height -= config.group_bar_height; + geom.y += config.group_bar_height; + } + + resize(c, geom, 0); } void exit_scroller_stack(Client *c) { @@ -5531,7 +5608,7 @@ void exit_scroller_stack(Client *c) { struct ScrollerStackNode *n = find_scroller_node(st, c); if (n) { scroller_node_remove(st, n); - return; /* 节点已移除,客户端指针已在函数内清空 */ + return; } } } @@ -5559,6 +5636,12 @@ void setmaximizescreen(Client *c, int32_t maximizescreen, bool rearrange) { maximizescreen_box.y = c->mon->w.y + config.gappov; maximizescreen_box.width = c->mon->w.width - 2 * config.gappoh; maximizescreen_box.height = c->mon->w.height - 2 * config.gappov; + + if ((c->group_next || c->group_prev) && c->group_bar) { + maximizescreen_box.height -= config.group_bar_height; + maximizescreen_box.y += config.group_bar_height; + } + wlr_scene_node_raise_to_top(&c->scene->node); if (!is_scroller_layout(c->mon) || c->isfloating) resize(c, maximizescreen_box, 0); @@ -5569,7 +5652,10 @@ void setmaximizescreen(Client *c, int32_t maximizescreen, bool rearrange) { } wlr_scene_node_reparent(&c->scene->node, - layers[c->isfloating ? LyrTop : LyrTile]); + layers[c->ismaximizescreen ? LyrMaximize + : c->isfloating ? LyrTop + : LyrTile]); + client_reparent_group(c); if (!c->force_fakemaximize && !c->ismaximizescreen) { client_set_maximized(c, false); @@ -5639,6 +5725,8 @@ void setfullscreen(Client *c, int32_t fullscreen, layers[fullscreen || c->isfloating ? LyrTop : LyrTile]); } + client_reparent_group(c); + if (rearrange) arrange(c->mon, false, false); } @@ -6501,7 +6589,12 @@ void unmapnotify(struct wl_listener *listener, void *data) { if (c->swallowedby) { c->swallowedby->mon = c->mon; - swallow(c->swallowedby, c); + client_replace(c->swallowedby, c, false); + } else if ((c->group_next || c->group_prev) && c->isgroupfocusing) { + Client *group_replacement = + c->group_next ? c->group_next : c->group_prev; + group_replacement->mon = c->mon; + client_replace(group_replacement, c, false); } else { scroller_remove_client(c); dwindle_remove_client(c); @@ -6550,7 +6643,11 @@ void unmapnotify(struct wl_listener *listener, void *data) { if (client_is_unmanaged(c)) { #ifdef XWAYLAND if (client_is_x11(c)) { - wl_list_remove(&c->set_geometry.link); + if (c->set_geometry.link.prev && c->set_geometry.link.next && + c->set_geometry.link.prev != &c->set_geometry.link) { + wl_list_remove(&c->set_geometry.link); + wl_list_init(&c->set_geometry.link); + } } #endif if (c == exclusive_focus) @@ -6558,11 +6655,33 @@ void unmapnotify(struct wl_listener *listener, void *data) { if (client_surface(c) == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); } else { - if (!c->swallowing) - wl_list_remove(&c->link); + + bool is_in_group = c->group_next || c->group_prev; + + if (c->group_next && !c->isgroupfocusing) { + c->group_next->group_prev = c->group_prev; + } + + if (c->group_prev && !c->isgroupfocusing) { + c->group_prev->group_next = c->group_next; + } + + c->group_next = NULL; + c->group_prev = NULL; + + if (!c->swallowing && (!is_in_group || c->isgroupfocusing)) { + if (c->link.prev && c->link.next && c->link.prev != &c->link) { + wl_list_remove(&c->link); + wl_list_init(&c->link); + } + } setmon(c, NULL, 0, true); - if (!c->swallowing) - wl_list_remove(&c->flink); + if (!c->swallowing && (!is_in_group || c->isgroupfocusing)) { + if (c->flink.prev && c->flink.next && c->flink.prev != &c->flink) { + wl_list_remove(&c->flink); + wl_list_init(&c->flink); + } + } } if (c->foreign_toplevel) { @@ -6587,6 +6706,15 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->swallowing = NULL; } + if (c->jump_label_node) { + mango_jump_label_node_destroy(c->jump_label_node); + c->jump_label_node = NULL; + } + if (c->group_bar) { + mango_group_bar_destroy(c->group_bar); + c->group_bar = NULL; + } + if (c->image_capture_tree) { wlr_scene_node_destroy(&c->image_capture_tree->node); c->image_capture_tree = NULL; @@ -6595,18 +6723,9 @@ void unmapnotify(struct wl_listener *listener, void *data) { wlr_scene_node_destroy(&c->image_capture_scene->tree.node); c->image_capture_scene = NULL; } + c->image_capture_source = NULL; - - 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; - } + init_client_properties(c); wlr_scene_node_destroy(&c->scene->node); printstatus(IPC_WATCH_ARRANGGE); @@ -6755,7 +6874,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); + mango_group_bar_update(c->group_bar, 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) {