diff --git a/src/animation/tag.h b/src/animation/tag.h index df1fb8f6..c46b9fd0 100644 --- a/src/animation/tag.h +++ b/src/animation/tag.h @@ -15,7 +15,11 @@ void set_tagin_animation(Monitor *m, Client *c) { return; } - if (m->pertag->curtag > m->pertag->prevtag) { + bool going_forward = m->carousel_anim_dir + ? m->carousel_anim_dir > 0 + : m->pertag->curtag > m->pertag->prevtag; + + if (going_forward) { c->animainit_geom.x = config.tag_animation_direction == VERTICAL ? c->animation.current.x @@ -75,7 +79,10 @@ void set_tagout_animation(Monitor *m, Client *c) { return; } - if (m->pertag->curtag > m->pertag->prevtag) { + bool going_forward = m->carousel_anim_dir + ? m->carousel_anim_dir > 0 + : m->pertag->curtag > m->pertag->prevtag; + if (going_forward) { c->pending = c->geom; c->pending.x = config.tag_animation_direction == VERTICAL diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ed6310a8..9ed17719 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -306,6 +306,7 @@ typedef struct { uint32_t gappoh; uint32_t gappov; uint32_t borderpx; + int32_t tag_carousel; float scratchpad_width_ratio; float scratchpad_height_ratio; float rootcolor[4]; @@ -1697,6 +1698,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, "tag_carousel") == 0) { + config->tag_carousel = atoi(value); } else if (strcmp(key, "rootcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { @@ -3342,6 +3345,7 @@ void set_value_default() { config.idleinhibit_ignore_visible = 0; config.borderpx = 4; + config.tag_carousel = 0; config.overviewgappi = 5; config.overviewgappo = 30; config.cursor_hide_timeout = 0; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 76feee64..6f9213b8 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1242,9 +1242,18 @@ int32_t tagtoleft(const Arg *arg) { return 0; if (selmon->sel != NULL && - __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && - selmon->tagset[selmon->seltags] > 1) { - tag(&(Arg){.ui = selmon->tagset[selmon->seltags] >> 1, .i = arg->i}); + __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1) { + uint32_t target = selmon->tagset[selmon->seltags] >> 1; + + if (target == 0) { + if (!config.tag_carousel) + return 0; + target = (1 << (LENGTH(tags) - 1)) & TAGMASK; + selmon->carousel_anim_dir = -1; + } + + tag(&(Arg){.ui = target & TAGMASK, .i = arg->i}); + selmon->carousel_anim_dir = 0; } return 0; } @@ -1254,9 +1263,18 @@ int32_t tagtoright(const Arg *arg) { return 0; if (selmon->sel != NULL && - __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && - selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { - tag(&(Arg){.ui = selmon->tagset[selmon->seltags] << 1, .i = arg->i}); + __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1) { + uint32_t target = selmon->tagset[selmon->seltags] << 1; + + if (!(target & TAGMASK)) { + if (!config.tag_carousel) + return 0; + target = 1; + selmon->carousel_anim_dir = 1; + } + + tag(&(Arg){.ui = target & TAGMASK, .i = arg->i}); + selmon->carousel_anim_dir = 0; } return 0; } @@ -1499,22 +1517,24 @@ int32_t viewtoleft(const Arg *arg) { if (!selmon) return 0; - uint32_t target = selmon->tagset[selmon->seltags]; - - if (selmon->isoverview || selmon->pertag->curtag == 0) { + if (selmon->isoverview || selmon->pertag->curtag == 0) return 0; - } + uint32_t target = selmon->tagset[selmon->seltags]; target >>= 1; if (target == 0) { - return 0; + if (!config.tag_carousel) + return 0; + target = (1 << (LENGTH(tags) - 1)) & TAGMASK; + selmon->carousel_anim_dir = -1; } - if (!selmon || (target) == selmon->tagset[selmon->seltags]) + if (target == selmon->tagset[selmon->seltags]) return 0; view(&(Arg){.ui = target & TAGMASK, .i = arg->i}, true); + selmon->carousel_anim_dir = 0; return 0; } @@ -1522,19 +1542,24 @@ int32_t viewtoright(const Arg *arg) { if (!selmon) return 0; - if (selmon->isoverview || selmon->pertag->curtag == 0) { + if (selmon->isoverview || selmon->pertag->curtag == 0) return 0; - } + uint32_t target = selmon->tagset[selmon->seltags]; target <<= 1; - if (!selmon || (target) == selmon->tagset[selmon->seltags]) - return 0; if (!(target & TAGMASK)) { - return 0; + if (!config.tag_carousel) + return 0; + target = 1; + selmon->carousel_anim_dir = 1; } + if (target == selmon->tagset[selmon->seltags]) + return 0; + view(&(Arg){.ui = target & TAGMASK, .i = arg->i}, true); + selmon->carousel_anim_dir = 0; return 0; } diff --git a/src/mango.c b/src/mango.c index e63fa86e..3bdddc80 100644 --- a/src/mango.c +++ b/src/mango.c @@ -553,6 +553,7 @@ struct Monitor { char last_surface_ws_name[256]; struct wlr_ext_workspace_group_handle_v1 *ext_group; bool iscleanuping; + int8_t carousel_anim_dir; }; typedef struct { @@ -3216,6 +3217,7 @@ void createmon(struct wl_listener *listener, void *data) { m->skiping_frame = false; m->resizing_count_pending = 0; m->resizing_count_current = 0; + m->carousel_anim_dir = 0; m->wlr_output = wlr_output; m->wlr_output->data = m;