mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-06-30 13:14:45 -04:00
feat: support group
This commit is contained in:
parent
0fc7559c3c
commit
d1cab2c4b7
14 changed files with 483 additions and 233 deletions
190
src/mango.c
190
src/mango.c
|
|
@ -414,7 +414,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;
|
||||
|
|
@ -466,6 +465,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 {
|
||||
|
|
@ -804,7 +806,7 @@ 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);
|
||||
|
|
@ -936,6 +938,8 @@ 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_tab_bar(Client *c, int32_t x, int32_t y, int32_t width,
|
||||
int32_t height);
|
||||
|
||||
#include "data/static_keymap.h"
|
||||
#include "dispatch/bind_declare.h"
|
||||
|
|
@ -1273,7 +1277,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;
|
||||
|
|
@ -1288,10 +1292,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_tab_bar_node_set_focus(c->tab_bar_node, true);
|
||||
}
|
||||
|
||||
if (w->overview_scene_surface) {
|
||||
wlr_scene_node_destroy(&w->scene_surface->node);
|
||||
w->scene_surface = w->overview_scene_surface;
|
||||
|
|
@ -1302,13 +1339,36 @@ void swallow(Client *c, Client *w) {
|
|||
overview_backup_surface(c);
|
||||
}
|
||||
|
||||
if (w->tab_bar_node) {
|
||||
if (w->tab_bar_node && !isgroupaction) {
|
||||
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);
|
||||
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,
|
||||
|
|
@ -1357,12 +1417,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;
|
||||
|
|
@ -1780,11 +1838,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;
|
||||
}
|
||||
|
|
@ -1799,7 +1855,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);
|
||||
}
|
||||
|
||||
|
|
@ -1836,7 +1895,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);
|
||||
}
|
||||
|
|
@ -2425,7 +2487,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
|
|||
MangoNodeData *mangonodedata = (MangoNodeData *)node->data;
|
||||
if (mangonodedata->type == MANGO_TITLE_NODE) {
|
||||
Client *c = mangonodedata->node_data;
|
||||
focusclient(c, 1);
|
||||
client_focus_group_member(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2592,6 +2654,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);
|
||||
}
|
||||
|
|
@ -2602,6 +2665,8 @@ void cleanuplisteners(void) {
|
|||
}
|
||||
|
||||
void cleanup(void) {
|
||||
allow_frame_scheduling = false;
|
||||
|
||||
ipc_cleanup();
|
||||
cleanuplisteners();
|
||||
#ifdef XWAYLAND
|
||||
|
|
@ -3519,30 +3584,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);
|
||||
}
|
||||
|
||||
|
|
@ -4456,9 +4513,11 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx,
|
|||
}
|
||||
|
||||
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->overview_scene_surface = NULL;
|
||||
|
|
@ -4637,6 +4696,8 @@ mapnotify(struct wl_listener *listener, void *data) {
|
|||
wlr_scene_node_set_enabled(&c->splitindicator[i]->node, false);
|
||||
}
|
||||
|
||||
client_add_tab_bar_node(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);
|
||||
|
|
@ -5641,11 +5702,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->tab_bar_node) {
|
||||
geom.height -= config.tab_bar_height;
|
||||
geom.y += config.tab_bar_height;
|
||||
}
|
||||
|
||||
resize(c, geom, 0);
|
||||
}
|
||||
|
||||
void exit_scroller_stack(Client *c) {
|
||||
|
|
@ -5658,7 +5726,7 @@ void exit_scroller_stack(Client *c) {
|
|||
struct ScrollerStackNode *n = find_scroller_node(st, c);
|
||||
if (n) {
|
||||
scroller_node_remove(st, n);
|
||||
return; /* 节点已移除,客户端指针已在函数内清空 */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5686,6 +5754,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->tab_bar_node) {
|
||||
maximizescreen_box.height -= config.tab_bar_height;
|
||||
maximizescreen_box.y += config.tab_bar_height;
|
||||
}
|
||||
|
||||
wlr_scene_node_raise_to_top(&c->scene->node);
|
||||
if (!is_scroller_layout(c->mon) || c->isfloating)
|
||||
resize(c, maximizescreen_box, 0);
|
||||
|
|
@ -6650,7 +6724,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);
|
||||
|
|
@ -6699,7 +6778,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)
|
||||
|
|
@ -6707,11 +6790,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) {
|
||||
|
|
@ -6731,8 +6836,6 @@ void unmapnotify(struct wl_listener *listener, void *data) {
|
|||
c->swallowing = 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;
|
||||
|
|
@ -6744,6 +6847,9 @@ void unmapnotify(struct wl_listener *listener, void *data) {
|
|||
|
||||
wlr_scene_node_destroy(&c->image_capture_scene_surface->buffer->node);
|
||||
wlr_scene_node_destroy(&c->image_capture_scene->tree.node);
|
||||
|
||||
init_client_properties(c);
|
||||
|
||||
wlr_scene_node_destroy(&c->scene->node);
|
||||
printstatus(IPC_WATCH_ARRANGGE);
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue