From 9bcdf7860ab5c3aaab177ec28881a5cff1fb499f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 5 Mar 2025 16:26:44 +0800 Subject: [PATCH] feat: add swallow to windowrule --- README.md | 2 + client.h | 12 +++++ config.conf | 2 + maomao.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++--- parse_config.h | 10 ++++ 5 files changed, 149 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d348e15b..26010a8f 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ See below for more features. - monitor : type-num(0-99999) - width : type-num(0-9999) - height : type-num(0-9999) +- isterm : type-num(0 or 1) it will be swallowed by the sub window +- noswallow: type-num(0 or 1) don't swallow the isterm window # some special feature - hycov like overview diff --git a/client.h b/client.h index f1e2ab54..18000b0d 100644 --- a/client.h +++ b/client.h @@ -131,6 +131,18 @@ client_get_appid(Client *c) return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken"; } +static inline int +client_get_pid(Client *c) +{ + pid_t pid; +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->pid; +#endif + wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); + return pid; +} + static inline void client_get_clip(Client *c, struct wlr_box *clip) { diff --git a/config.conf b/config.conf index 97232b8e..ac76a2d0 100644 --- a/config.conf +++ b/config.conf @@ -99,6 +99,8 @@ tags=id:9,layout_name:tile # monitor : type-int(0-99999) # width : type-num(0-9999) # height : type-num(0-9999) +# isterm : type-num (0 or 1) -- when new window open, will replace it, and will restore after the sub window exit +# nnoswallow : type-num(0 or 1) -- if enable, this window wll not replace isterm window when it was open by isterm window # example # windowrule=isfloating:1,appid:yesplaymusic diff --git a/maomao.c b/maomao.c index a325a262..fb385335 100644 --- a/maomao.c +++ b/maomao.c @@ -175,7 +175,9 @@ struct dwl_animation { typedef struct Pertag Pertag; typedef struct Monitor Monitor; -typedef struct { + +typedef struct Client Client; +struct Client { /* Must keep these three elements in this order */ unsigned int type; /* XDGShell or X11* */ struct wlr_box geom, pending, oldgeom, animainit_geom, overview_backup_geom, @@ -244,9 +246,12 @@ typedef struct { bool need_output_flush; struct dwl_animation animation; bool is_fadeout_client; + int isterm, noswallow; // struct wl_event_source *timer_tick; + pid_t pid; + Client *swallowing, *swallowedby; +}; -} Client; typedef struct { struct wl_list link; @@ -521,6 +526,10 @@ 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); static void clear_fullscreen_flag(Client *c); +static pid_t getparentprocess(pid_t p); +static int isdescprocess(pid_t p, pid_t c); +static Client *termforwin(Client *w); +static void swallow(Client *c, Client *w); static void warp_cursor_to_selmon(const Monitor *m); unsigned int want_restore_fullscreen(Client *target_client); @@ -566,6 +575,8 @@ void defaultgaps(const Arg *arg); void buffer_set_size(Client *c, animationScale scale_data); void snap_scene_buffer_apply_size(struct wlr_scene_buffer *buffer, int sx, int sy, void *data); +void client_set_pending_state(Client *c); + // int timer_tick_action(void *data); #include "dispatch.h" @@ -1243,6 +1254,64 @@ void reset_foreign_tolevel(Client *c) { } } +pid_t +getparentprocess(pid_t p) +{ + unsigned int v = 0; + + FILE *f; + char buf[256]; + snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p); + + if (!(f = fopen(buf, "r"))) + return 0; + + fscanf(f, "%*u %*s %*c %u", &v); + fclose(f); + + return (pid_t)v; +} + +int +isdescprocess(pid_t p, pid_t c) +{ + while (p != c && c != 0) + c = getparentprocess(c); + + return (int)c; +} + +Client * +termforwin(Client *w) +{ + Client *c; + + if (!w->pid || w->isterm || w->noswallow) + return NULL; + + wl_list_for_each(c, &fstack, flink) + if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid)) + return c; + + return NULL; +} + +void +swallow(Client *c, Client *w) +{ + c->bw = w->bw; + c->isfloating = w->isfloating; + c->isurgent = w->isurgent; + c->isfullscreen = w->isfullscreen; + c->ismaxmizescreen = w->ismaxmizescreen; + c->tags = w->tags; + c->geom = w->geom; + wl_list_insert(&w->link, &c->link); + wl_list_insert(&w->flink, &c->flink); + wlr_scene_node_set_enabled(&w->scene->node, 0); + wlr_scene_node_set_enabled(&c->scene->node, 1); +} + void toggle_scratchpad(const Arg *arg) { Client *c; wl_list_for_each(c, &clients, link) { @@ -1408,6 +1477,8 @@ applyrules(Client *c) { if (!(title = client_get_title(c))) title = broken; + c->pid = client_get_pid(c); + for (ji = 0; ji < config.window_rules_count; ji++) { if (config.window_rules_count < 1) break; @@ -1415,6 +1486,8 @@ applyrules(Client *c) { if ((r->title && strstr(title, r->title)) || (r->id && strstr(appid, r->id))) { + c->isterm = r->isterm > 0 ? r->isterm : c->isterm; + c->noswallow = r->noswallow > 0? r->noswallow : c->noswallow; c->isfloating = r->isfloating > 0 ? r->isfloating : c->isfloating; c->animation_type = r->animation_type == NULL ? c->animation_type : r->animation_type; @@ -1438,10 +1511,26 @@ applyrules(Client *c) { } } } - + if (!client_surface(c)->mapped) return; + if (!c->noswallow && !client_is_float_type(c) + && !c->surface.xdg->initial_commit) { + Client *p = termforwin(c); + if (p) { + 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); + mon = p->mon; + newtags = p->tags; + } + } + wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); setmon(c, mon, newtags); @@ -4343,6 +4432,15 @@ void resize(Client *c, struct wlr_box geo, int interact) { if (!c->animation.tagouting && !c->iskilling) { c->pending = c->geom; } + + if (c->swallowedby && c->animation.action == OPEN) { + c->animainit_geom = c->swallowedby->animation.current; + } + + if (c->swallowing) { + c->animainit_geom = c->geom; + } + // 开始应用动画设置 client_set_pending_state(c); @@ -4437,7 +4535,7 @@ setfloating(Client *c, int floating) { target_box = c->geom; - if (floating == 1) { + if (c->istiled && !c->swallowing) { if (c->istiled) { target_box.height = target_box.height * 0.8; target_box.width = target_box.width * 0.8; @@ -5896,6 +5994,10 @@ void unmapnotify(struct wl_listener *listener, void *data) { if (animations) init_fadeout_client(c); + if (c->swallowedby) { + swallow(c->swallowedby, c); + } + if (c == grabc) { cursor_mode = CurNormal; grabc = NULL; @@ -5924,9 +6026,11 @@ void unmapnotify(struct wl_listener *listener, void *data) { if (client_surface(c) == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); } else { - wl_list_remove(&c->link); + if (!c->swallowing) + wl_list_remove(&c->link); setmon(c, NULL, 0); - wl_list_remove(&c->flink); + if (!c->swallowing) + wl_list_remove(&c->flink); } if (c->foreign_toplevel) { @@ -5934,6 +6038,19 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->foreign_toplevel = NULL; } + if (c->swallowedby) { + c->swallowedby->prev = c->geom; + setfullscreen(c->swallowedby, c->isfullscreen); + setmaxmizescreen(c->swallowedby, c->ismaxmizescreen); + c->swallowedby->swallowing = NULL; + c->swallowedby = NULL; + } + + if (c->swallowing) { + c->swallowing->swallowedby = NULL; + c->swallowing = NULL; + } + // wl_event_source_remove(c->timer_tick); wlr_scene_node_destroy(&c->scene->node); printstatus(); diff --git a/parse_config.h b/parse_config.h index 87313462..9e42364b 100644 --- a/parse_config.h +++ b/parse_config.h @@ -19,6 +19,8 @@ typedef struct { int monitor; int width; int height; + int isterm; + int noswallow; } ConfigWinRule; typedef struct { @@ -29,6 +31,8 @@ typedef struct { int rr; // 旋转和翻转(假设为整数) float scale; // 显示器缩放比例 int x, y; // 显示器位置 + int isterm; + int noswallow; } ConfigMonitorRule; typedef struct { @@ -783,6 +787,8 @@ void parse_config_line(Config *config, const char *line) { rule->isfloating = -1; rule->isfullscreen = -1; rule->isnoborder = -1; + rule->isterm = -1; + rule->noswallow = -1; rule->monitor = -1; rule->width = -1; rule->height = -1; @@ -818,6 +824,10 @@ void parse_config_line(Config *config, const char *line) { rule->height = atoi(val); } else if (strcmp(key, "isnoborder") == 0) { rule->isnoborder = atoi(val); + } else if (strcmp(key, "isterm") == 0) { + rule->isterm = atoi(val); + } else if (strcmp(key, "noswallow") == 0) { + rule->noswallow = atoi(val); } else if (strcmp(key, "scroller_proportion") == 0) { rule->scroller_proportion = atof(val); } else if (strcmp(key, "isfullscreen") == 0) {