diff --git a/docs/window-management/layouts.md b/docs/window-management/layouts.md index 02f218a3..43585620 100644 --- a/docs/window-management/layouts.md +++ b/docs/window-management/layouts.md @@ -117,6 +117,18 @@ dwindle_drop_simple_split=1 --- +## Monocle Layout + +The Monocle layout is similar to the Center Tile layout, but it places windows in a single column instead of a row. + +### Configuration + +| Setting | Default | Description | +| :--- | :--- | :--- | +| `monocle_new_in_group` | `0` | New windows are auto grouped in the focused window. | + +--- + ## Switching Layouts | Setting | Default | Description | | :--- | :--- | :--- | diff --git a/src/action/client.h b/src/action/client.h index 85ab1aaf..71d9fed9 100644 --- a/src/action/client.h +++ b/src/action/client.h @@ -137,6 +137,9 @@ void client_add_group_bar(Client *c) { } void client_focus_group_member(Client *c) { + if (!c) + return; + if (!c->group_prev && !c->group_next) return; @@ -191,7 +194,8 @@ void client_check_tab_node_visible(Client *c) { 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)) { + (!is_monocle_layout(c->mon) || config.monocle_new_in_group || + c == c->mon->sel)) { wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node, true); } else { diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 959ff095..56dbe68d 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -264,6 +264,9 @@ typedef struct { int32_t dwindle_manual_split; float dwindle_split_ratio; + /* monocle layoput */ + int32_t monocle_new_in_group; + int32_t hotarea_size; int32_t hotarea_corner; int32_t enable_hotarea; @@ -1729,6 +1732,8 @@ bool parse_option(Config *config, char *key, char *value) { config->dwindle_manual_split = atoi(value); } else if (strcmp(key, "dwindle_split_ratio") == 0) { config->dwindle_split_ratio = atof(value); + } else if (strcmp(key, "monocle_new_in_group") == 0) { + config->monocle_new_in_group = atoi(value); } else if (strcmp(key, "hotarea_size") == 0) { config->hotarea_size = atoi(value); } else if (strcmp(key, "hotarea_corner") == 0) { @@ -3509,6 +3514,8 @@ void override_config(void) { config.dwindle_manual_split = CLAMP_INT(config.dwindle_manual_split, 0, 1); config.dwindle_split_ratio = CLAMP_FLOAT(config.dwindle_split_ratio, 0.05f, 0.95f); + config.monocle_new_in_group = CLAMP_INT(config.monocle_new_in_group, 0, 1); + config.hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000); config.hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3); config.enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1); @@ -3678,6 +3685,8 @@ void set_value_default() { config.dwindle_manual_split = 0; config.dwindle_split_ratio = 0.5f; + config.monocle_new_in_group = 0; + config.log_level = WLR_ERROR; config.numlockon = 0; config.capslock = 0; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 9312b12c..ec982303 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -156,28 +156,20 @@ int32_t focusdir(const Arg *arg) { return 0; } -int32_t groupjoin(const Arg *arg) { - - if (!selmon) - return 0; +void group_join_client(Client *need_join_client, Client *need_replace_client) { Monitor *oldmon = NULL; - - Client *need_join_client = arg->tc ? arg->tc : selmon->sel; - if (!need_join_client || !need_join_client->mon) - return 0; - - if (need_join_client->mon->isoverview) - return 0; - - Client *need_replace_client = NULL; - need_replace_client = direction_select(arg); - if (!need_replace_client || !need_replace_client->mon) - return 0; + return; if (need_join_client == need_replace_client) - return 0; + return; + + if (!need_join_client) + return; + + if (need_join_client->mon && need_join_client->mon->isoverview) + return; if (need_join_client->group_next || need_join_client->group_prev) { groupleave(&(Arg){.tc = need_join_client}); @@ -209,7 +201,19 @@ int32_t groupjoin(const Arg *arg) { if (oldmon) { arrange(oldmon, false, false); } +} +int32_t groupjoin(const Arg *arg) { + + if (!selmon) + return 0; + + Client *need_join_client = arg->tc ? arg->tc : selmon->sel; + + Client *need_replace_client = NULL; + need_replace_client = direction_select(arg); + + group_join_client(need_join_client, need_replace_client); return 0; } @@ -345,16 +349,57 @@ int32_t focusstack(const Arg *arg) { if (!sel) return 0; + if (arg->i == NEXT) { tc = get_next_stack_client(sel, false); } else { tc = get_next_stack_client(sel, true); } + if (!sel->mon->isoverview) { + if (!sel->group_next && !sel->group_prev) { + if (arg->i == NEXT) { + tc = client_get_group_head(tc); + if (tc) + client_focus_group_member(tc); + } else { + tc = client_get_group_tail(tc); + if (tc) + client_focus_group_member(tc); + } + } else { + if (arg->i == NEXT) { + if (sel->group_next) { + tc = sel->group_next; + } else if (!tc) { + tc = client_get_group_head(sel); + } else { + tc = client_get_group_head(tc); + } + if (tc) { + client_focus_group_member(tc); + } + } + if (arg->i == PREV) { + if (sel->group_prev) { + tc = sel->group_prev; + } else if (!tc) { + tc = client_get_group_tail(sel); + } else { + tc = client_get_group_tail(tc); + } + if (tc) { + client_focus_group_member(tc); + } + } + } + } + if (!tc) return 0; focusclient(tc, 1); + if (config.warpcursor) warp_cursor(tc); return 0; diff --git a/src/fetch/client.h b/src/fetch/client.h index e7d8e673..333b6302 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -320,6 +320,17 @@ Client *focustop(Monitor *m) { return NULL; } +Client *focustiletop(Monitor *m) { + Client *c = NULL; + wl_list_for_each(c, &fstack, flink) { + if (c->iskilling || c->isunglobal || !ISSCROLLTILED(c)) + continue; + if (VISIBLEON(c, m)) + return c; + } + return NULL; +} + Client *get_next_stack_client(Client *c, bool reverse) { if (!c || !c->mon) return NULL; @@ -454,4 +465,30 @@ Client *get_focused_stack_client(Client *sc, Client *custom_focus_client) { } } return sc; +} + +Client *client_get_group_head(Client *c) { + if (!c || !c->mon) + return NULL; + + Client *head = c; + + while (head->group_prev) { + head = head->group_prev; + } + + return head; +} + +Client *client_get_group_tail(Client *c) { + if (!c || !c->mon) + return NULL; + + Client *tail = c; + + while (tail->group_next) { + tail = tail->group_next; + } + + return tail; } \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 35f9266e..3139a857 100644 --- a/src/mango.c +++ b/src/mango.c @@ -961,6 +961,8 @@ static bool mango_scene_output_commit(struct wlr_scene_output *scene_output, struct wlr_output_state *state); static bool mango_output_commit(Monitor *m); static bool check_tearing_frame_allow(Monitor *m); +static Client *client_get_group_head(Client *c); +static Client *client_get_group_tail(Client *c); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -1891,6 +1893,11 @@ void applyrules(Client *c) { wl_list_insert(fstack.prev, &c->flink); } + if (config.monocle_new_in_group && mon && ISTILED(c) && + is_monocle_layout(mon)) { + group_join_client(c, focustiletop(mon)); + } + setmon(c, mon, newtags, should_init_get_focus); if (!c->isfloating) {