Derive master-stack geometry from one layout description

5ca9d73f3029b9dabcc194863d7f9fb7c3e71f07
Alexis Sellier committed ago 1 parent 6b057b8f
swm.c +85 -61
289 289
typedef struct {
290 290
    void (*arrange)(monitor_t *);
291 291
    bool cycle;
292 292
} layout_t;
293 293
294 +
/* Geometry of a master-stack layout. */
295 +
typedef struct {
296 +
    int  side;   /* One of the SWM_MASTER_* sides. */
297 +
    bool rotate; /* The master area runs along the top or bottom edge. */
298 +
    bool flip;   /* The master area sits on the far edge of its axis. */
299 +
} master_layout_t;
300 +
294 301
struct monitor_t {
295 302
    struct wl_list           link;
296 303
    struct wlr_output       *wlr_output;
297 304
    struct wlr_scene_output *scene_output;
298 305
    struct wlr_scene_rect   *fullscreen_bg; /* Hides other layers behind fullscreen windows. */
616 623
static void       setup(void);
617 624
static void       spawn(const arg_t *arg);
618 625
static void       expand_argv(const char *const *argv, char **expanded, char *storage);
619 626
static void       swap_client(const arg_t *arg);
620 627
static void       stack_config(const arg_t *arg);
621 -
static void       stack_master(monitor_t *m, int rot, int flip);
628 +
static void       stack_master(monitor_t *m, int side);
622 629
static void       start_drag(struct wl_listener *listener, void *data);
623 630
static void       tag(const arg_t *arg);
624 631
static void       tag_monitor(const arg_t *arg);
625 632
static void       toggle_floating(const arg_t *arg);
626 633
static void       toggle_fullscreen(const arg_t *arg);
1606 1613
        j++;
1607 1614
    }
1608 1615
    return count;
1609 1616
}
1610 1617
1611 -
/* Return the active master boundary for a tiled workspace. */
1612 -
static bool tiled_resize_boundary(monitor_t *m, int x, int y, bool *horizontal) {
1613 -
    client_t      *c;
1614 -
    workspace_t   *ws;
1615 -
    stack_state_t *st;
1616 -
    int            boundary, count = 0, masters;
1617 -
    bool           rotate, flip;
1618 +
/* Return whether a master side runs along the top or bottom edge. */
1619 +
static bool master_rotates(int side) {
1620 +
    return side == SWM_MASTER_TOP || side == SWM_MASTER_BOTTOM;
1621 +
}
1622 +
1623 +
/* Return whether a master side sits on the far edge of its axis. */
1624 +
static bool master_flips(int side) {
1625 +
    return side == SWM_MASTER_RIGHT || side == SWM_MASTER_BOTTOM;
1626 +
}
1618 1627
1619 -
    if (!m || !(ws = m->ws) || !ws->lt || !ws->lt->arrange || ws->lt->arrange == max_stack ||
1620 -
        x < m->w.x || x >= m->w.x + m->w.width || y < m->w.y || y >= m->w.y + m->w.height)
1628 +
/* Describe a master-stack layout, or report that it is not one. */
1629 +
static bool layout_master(const layout_t *lt, master_layout_t *ml) {
1630 +
    if (!lt || !lt->arrange)
1621 1631
        return false;
1622 1632
1623 -
    rotate = ws->lt->arrange == master_top || ws->lt->arrange == master_bottom;
1624 -
    flip   = ws->lt->arrange == master_right || ws->lt->arrange == master_bottom;
1633 +
    if (lt->arrange == master_left)
1634 +
        ml->side = SWM_MASTER_LEFT;
1635 +
    else if (lt->arrange == master_top)
1636 +
        ml->side = SWM_MASTER_TOP;
1637 +
    else if (lt->arrange == master_right)
1638 +
        ml->side = SWM_MASTER_RIGHT;
1639 +
    else if (lt->arrange == master_bottom)
1640 +
        ml->side = SWM_MASTER_BOTTOM;
1641 +
    else
1642 +
        return false;
1643 +
1644 +
    ml->rotate = master_rotates(ml->side);
1645 +
    ml->flip   = master_flips(ml->side);
1646 +
    return true;
1647 +
}
1648 +
1649 +
/* Return the enabled layout with its master area on a side, if any. */
1650 +
static const layout_t *layout_from_side(int side) {
1651 +
    master_layout_t ml;
1652 +
    size_t          i;
1653 +
1654 +
    for (i = 0; i < LENGTH(layouts); i++) {
1655 +
        if (layout_master(&layouts[i], &ml) && ml.side == side)
1656 +
            return &layouts[i];
1657 +
    }
1658 +
    return nullptr;
1659 +
}
1660 +
1661 +
/* Return the active master boundary for a tiled workspace. */
1662 +
static bool tiled_resize_boundary(monitor_t *m, int x, int y, bool *horizontal) {
1663 +
    client_t       *c;
1664 +
    workspace_t    *ws;
1665 +
    stack_state_t  *st;
1666 +
    master_layout_t ml;
1667 +
    int             boundary, count = 0, masters;
1668 +
    bool            rotate, flip;
1625 1669
1626 -
    if (!rotate && ws->lt->arrange != master_left && ws->lt->arrange != master_right)
1670 +
    if (!m || !(ws = m->ws) || !layout_master(ws->lt, &ml) || x < m->w.x ||
1671 +
        x >= m->w.x + m->w.width || y < m->w.y || y >= m->w.y + m->w.height)
1627 1672
        return false;
1628 1673
1674 +
    rotate = ml.rotate;
1675 +
    flip   = ml.flip;
1676 +
1629 1677
    wl_list_for_each(c, &clients, link) if (VISIBLEON(c, m) && !c->is_floating && !c->is_fullscreen)
1630 1678
        count++;
1631 1679
1632 1680
    st      = rotate ? &ws->h : &ws->v;
1633 1681
    masters = MIN(MAX(st->mwin, 0), count);
4238 4286
static void tiled_resize_update(void) {
4239 4287
    monitor_t           *m = point_to_monitor(cursor->x, cursor->y);
4240 4288
    struct wlr_keyboard *keyboard;
4241 4289
    workspace_t         *ws;
4242 4290
    stack_state_t       *st;
4291 +
    master_layout_t      ml;
4243 4292
    int                  size, offset, value;
4244 4293
    bool                 horizontal, flip;
4245 4294
4246 4295
    if (cursor_mode != CURSOR_TILE_RESIZE) {
4247 4296
        if (cursor_mode == CURSOR_PRESSED)
4259 4308
    }
4260 4309
4261 4310
    if (!grabws || !grabws->mon)
4262 4311
        return;
4263 4312
4264 -
    ws   = grabws;
4313 +
    ws = grabws;
4314 +
4315 +
    if (!layout_master(ws->lt, &ml))
4316 +
        return;
4265 4317
    m    = ws->mon;
4266 4318
    st   = grab_horizontal ? &ws->h : &ws->v;
4267 -
    flip = ws->lt->arrange == master_right || ws->lt->arrange == master_bottom;
4319 +
    flip = ml.flip;
4268 4320
    size = grab_horizontal ? m->w.height : m->w.width;
4269 4321
4270 4322
    offset = grab_horizontal ? (int)round(cursor->y) - m->w.y : (int)round(cursor->x) - m->w.x;
4271 4323
    value  = tiled_resize_value(offset, size, flip);
4272 4324
5893 5945
5894 5946
/* Adjust the master size, master count, stack count, or layout direction. */
5895 5947
void stack_config(const arg_t *arg) {
5896 5948
    /* adjust the master/stack parameters of the focused workspace's
5897 5949
     * current layout. */
5898 -
    workspace_t    *ws;
5899 -
    stack_state_t  *st;
5900 -
    const layout_t *next        = nullptr;
5901 -
    void (*target)(monitor_t *) = nullptr;
5950 +
    workspace_t           *ws;
5951 +
    stack_state_t         *st;
5952 +
    const layout_t        *next;
5953 +
    master_layout_t        ml;
5902 5954
    struct swm_stack_state state;
5903 -
    int                    side, newside;
5904 -
    size_t                 i;
5955 +
    int                    newside;
5905 5956
5906 -
    if (!arg || !selmon || !(ws = selmon->ws))
5957 +
    if (!arg || !selmon || !(ws = selmon->ws) || !layout_master(ws->lt, &ml))
5907 5958
        return;
5908 -
5909 -
    if (ws->lt->arrange == master_left || ws->lt->arrange == master_right)
5910 -
        st = &ws->v;
5911 -
    else if (ws->lt->arrange == master_top || ws->lt->arrange == master_bottom)
5912 -
        st = &ws->h;
5913 -
    else
5914 -
        return;
5915 -
5916 -
    if (ws->lt->arrange == master_left)
5917 -
        side = SWM_MASTER_LEFT;
5918 -
    else if (ws->lt->arrange == master_top)
5919 -
        side = SWM_MASTER_TOP;
5920 -
    else if (ws->lt->arrange == master_right)
5921 -
        side = SWM_MASTER_RIGHT;
5922 -
    else
5923 -
        side = SWM_MASTER_BOTTOM;
5924 -
5959 +
    st    = ml.rotate ? &ws->h : &ws->v;
5925 5960
    state = (struct swm_stack_state){ st->msize, st->mwin, st->stacks };
5926 5961
5927 -
    if (!swm_stack_configure(&state, arg->i, side, &newside))
5962 +
    if (!swm_stack_configure(&state, arg->i, ml.side, &newside))
5928 5963
        return;
5929 5964
    *st = (stack_state_t){ state.msize, state.mwin, state.stacks };
5930 -
    if (newside != side)
5931 -
        target = newside == SWM_MASTER_LEFT    ? master_left
5932 -
                 : newside == SWM_MASTER_TOP   ? master_top
5933 -
                 : newside == SWM_MASTER_RIGHT ? master_right
5934 -
                                               : master_bottom;
5935 5965
5936 -
    if (target) {
5937 -
        for (i = 0; i < LENGTH(layouts); i++)
5938 -
5939 -
            if (layouts[i].arrange == target) {
5940 -
                next = &layouts[i];
5941 -
                break;
5942 -
            }
5943 -
        if (next) {
5944 -
            ws->prevlt = ws->lt;
5945 -
            ws->lt     = next;
5946 -
        }
5966 +
    if (newside != ml.side && (next = layout_from_side(newside))) {
5967 +
        ws->prevlt = ws->lt;
5968 +
        ws->lt     = next;
5947 5969
    }
5948 5970
    arrange(selmon);
5949 5971
    print_status();
5950 5972
}
5951 5973
5952 5974
/* Tile windows into a master area followed by evenly divided stacks. */
5953 -
void stack_master(monitor_t *m, int rot, int flip) {
5975 +
void stack_master(monitor_t *m, int side) {
5954 5976
    /* Master/stack tiler: a master area holding up to mwin
5955 5977
     * windows and a stacking area split into st->stacks columns. All
5956 5978
     * geometry is computed in "vertical" coordinates and transposed at
5957 5979
     * the end for the horizontal layout. */
5980 +
    bool                   rot  = master_rotates(side);
5981 +
    bool                   flip = master_flips(side);
5958 5982
    client_t              *c;
5959 5983
    stack_state_t         *st = rot ? &m->ws->h : &m->ws->v;
5960 5984
    struct swm_box         boxes[MAX_CLIENTS];
5961 5985
    struct swm_stack_state state = { st->msize, st->mwin, st->stacks };
5962 5986
    int                    n     = 0;
5973 5997
    }
5974 5998
}
5975 5999
5976 6000
/* Tile the master area along the bottom edge. */
5977 6001
void master_bottom(monitor_t *m) {
5978 -
    stack_master(m, 1, 1);
6002 +
    stack_master(m, SWM_MASTER_BOTTOM);
5979 6003
}
5980 6004
5981 6005
/* Tile the master area along the left edge. */
5982 6006
void master_left(monitor_t *m) {
5983 -
    stack_master(m, 0, 0);
6007 +
    stack_master(m, SWM_MASTER_LEFT);
5984 6008
}
5985 6009
5986 6010
/* Tile the master area along the right edge. */
5987 6011
void master_right(monitor_t *m) {
5988 -
    stack_master(m, 0, 1);
6012 +
    stack_master(m, SWM_MASTER_RIGHT);
5989 6013
}
5990 6014
5991 6015
/* Tile the master area along the top edge. */
5992 6016
void master_top(monitor_t *m) {
5993 -
    stack_master(m, 1, 0);
6017 +
    stack_master(m, SWM_MASTER_TOP);
5994 6018
}
5995 6019
5996 6020
/* Toggle the focused window between tiled and floating. */
5997 6021
void toggle_floating(const arg_t *arg) {
5998 6022
    client_t *sel = focus_top(selmon);