Derive master-stack geometry from one layout description
5ca9d73f3029b9dabcc194863d7f9fb7c3e71f07
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); |