mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-14 12:53:43 +01:00
120 lines
8.4 KiB
Markdown
120 lines
8.4 KiB
Markdown
# Resizing a tile by dragging its edge
|
|
|
|
A tiled window can be resized with the pointer: take hold of one of its edges or corners, drag
|
|
it, and let go. While the edge is dragged, the tiles next to it follow it. When it is let go,
|
|
komorebi moves the edges of the window's tile by as much as the pointer moved them, as
|
|
[`komorebic resize-edge`](cli/resize-edge.md) would, the tiles next to it give up or take the
|
|
room, and the window is put on its tile. This page says what komorebi does with a drag, the rules
|
|
it keeps to, and why each of them is there.
|
|
|
|
## What a drag does
|
|
|
|
1. KWin reports that the user took hold of a window to resize it, and the window manager records
|
|
the frame the window had at that moment.
|
|
2. When the user lets go, KWin reports the end of the drag, and the window manager compares the
|
|
frame the user left the window with to the frame it recorded, edge by edge: the left, the top,
|
|
the right and the bottom.
|
|
3. For each edge that moved, it asks the layout to move that edge of the tile by the same number
|
|
of pixels, outward or inward. A corner is two edges.
|
|
4. The workspace is tiled again: the dragged window goes onto its tile, wherever the user left it,
|
|
and so do its neighbors.
|
|
|
|
Between the start and the end, KWin reports every step of the drag with the frame the pointer
|
|
asks for, and the window manager does what it does at the end, from the same start, except that
|
|
it leaves the dragged window where the user has it: the neighbors follow the edge while it is
|
|
dragged. The animation effect ([Animation](usage/animation.md)) does not animate any window while
|
|
a user resize goes on, so the neighbors move at once.
|
|
|
|
## The rules
|
|
|
|
- **A drag is measured from where the window was when it began, not from its tile.** A window is
|
|
not always exactly on its tile: a terminal sizes itself to whole cells of its font and is a few
|
|
pixels short, and a window with a minimum size can be larger. Measured against the tile, a drag
|
|
of one edge of such a window would look as if the other edges had moved too, and those would be
|
|
resized as well.
|
|
- **Each edge is compared with its own start.** A rectangle in komorebi is a position and a size,
|
|
so the right and the bottom edges are worked out from them. Comparing the sizes instead would
|
|
make a drag of the left edge look like a drag of the right one.
|
|
- **The tile of the window that was dragged is resized**, which is not always the focused one: the
|
|
press that began the drag may not have given it the focus yet.
|
|
- **Only a tile is resized.** The window of a stack has the tile of the stack, so the drag
|
|
resizes that. A floating window and the window of a monocle are in no tile of the layout, and
|
|
are left as the user made them.
|
|
- **An edge with no neighbor does not move.** The left edge of the leftmost tile has nothing to
|
|
take room from: dragging it changes no tile, and the window is put back on its tile.
|
|
- **A drag that ends where it began changes nothing**, not even a tile next to it.
|
|
- **A drag is granted as far as it can go.** No tile is made narrower or shorter than a tenth of
|
|
the monitor's work area, or than it is already, so a drag further than a neighbor can give
|
|
moves the edge as far as the neighbor allows, and a drag that would shrink the window past that
|
|
shrinks it that far. The same bound applies to `komorebic resize-edge`, and a drag of any
|
|
length is granted, however narrow the dragged tile is.
|
|
- **The end of a resize is where the user took the edge.** KWin changes a window's frame once its
|
|
client has drawn at the new size, so when the user lets go the frame can still be short of the
|
|
pointer, and the frames KWin reports after that change it again before the window manager gets to
|
|
the end of the drag, which it may do while it is busy with an earlier event. The bridge keeps the
|
|
frame the user last asked for during the drag, the daemon keeps it apart from the window's frame,
|
|
and the window manager reads that one at the end, whenever it gets there; the window's frame
|
|
follows a moment later. The end of a move is the frame, and so is the end of a resize that had no
|
|
step.
|
|
|
|
## While the edge is dragged
|
|
|
|
- **Every step is worked out from the start of the drag**, not from the step before. When the user
|
|
takes hold of the edge, the window manager keeps the sizes the tiles had been given and where
|
|
the layout put them, and each step, and the end, starts from those: the drag so far is the
|
|
distance from the start. So a drag has the same result with its steps as without them, and a
|
|
drag that is taken back, to where it began or with Escape, puts the neighbors back where they
|
|
were.
|
|
- **The dragged window is the user's until they let go.** komorebi does not move it while the edge
|
|
is dragged, also when something else tiles the workspace, such as a window that opens.
|
|
- **A window that opens or closes part way through a drag stops the neighbors following.** The
|
|
layout the drag began on is not the layout there is any more; the end of the drag still resizes
|
|
the tile, on the layout there is then.
|
|
- **Only the newest step counts.** The pointer makes far more steps than the neighbors can follow:
|
|
the bridge sends one every 16 ms at most, the newest, and sends the last one of a burst when the
|
|
16 ms are over; the window manager keeps at most one step waiting, and reads where the edge is
|
|
when it gets to it. A step that is still waiting when the user lets go is not sent.
|
|
- **A move has no steps.** A window dragged by its title bar moves alone; the tiles change when it
|
|
is let go ([Moving windows](usage/moving-windows.md#by-dragging)).
|
|
- **KWin's snapping applies to the edge.** KWin snaps an edge the user drags to an edge of another
|
|
window within its snap zone, 10 pixels by default, and the tiles that follow the edge are about
|
|
that close to it with the default paddings, so the edge can end a few pixels past the pointer. A
|
|
window snap zone of 0, in KWin's window behavior settings, turns that off.
|
|
|
|
## The layouts
|
|
|
|
The layouts that move the edges are `komorebi-layouts` from
|
|
[komorebi](https://github.com/LGUG2Z/komorebi), at the revision `Cargo.toml` pins. That revision
|
|
has the fix of [LGUG2Z/komorebi#1765]: `DefaultLayout::resize` adds the whole adjustment to the
|
|
tile and leaves the bound to the window manager, which knows the other tiles. The window manager
|
|
grants the largest part of the adjustment that leaves every tile at least as large as the rule
|
|
above says (`WindowManager::resize_window`), looking for it by bisection, since the tiles only get
|
|
smaller as the adjustment grows. The BSP, columns, rows, vertical stack, right main vertical
|
|
stack, horizontal stack, ultrawide vertical stack and scrolling layouts can be resized this way;
|
|
the grid layout cannot, and in a layout some edges cannot move, such as the top and the bottom
|
|
of a column.
|
|
|
|
[LGUG2Z/komorebi#1765]: https://github.com/LGUG2Z/komorebi/issues/1765
|
|
|
|
## How it is tested
|
|
|
|
- `crates/komorebi-linux/tests/drag_resize.rs`, against the fake desktop: a drag of the split between two
|
|
tiles; a long drag of the narrow right-hand stack of the ultrawide vertical stack; a drag past
|
|
what the neighbor can give; a shrink past what the tile can lose; a drag of a window that is
|
|
short of its tile, which must not move the divider on its other side; a drag of a window that is
|
|
not the focused one; an edge with no neighbor; a drag that changed nothing; a corner; the edge
|
|
of a stack; a floating window and the window of a monocle; a drag whose frame had not got to
|
|
where the user took the edge when the window manager read the end.
|
|
- `crates/komorebi-linux/src/kwin/state.rs`: the end of a resize is the frame the user asked for and a frame
|
|
event after it does not change that, the end of a move is the frame, and the frame a drag began
|
|
with is kept while the frame changes.
|
|
- `vm-drag-resize`, in a Plasma session with a pointer device: edges and corners of three tiles
|
|
are dragged with the pointer, and the tiles are checked exactly (the dragged edge moved by what
|
|
the pointer moved, the neighbor's with it, nothing else), the frames within a cell of the
|
|
terminal's font.
|
|
- `crates/komorebi-linux/tests/live_resize.rs`, against the fake desktop: the neighbors follow a drag while it
|
|
goes on and the dragged window is left alone; the same result with steps as without; a drag
|
|
taken back; a step with no drag going on; a window that opens part way through.
|
|
- `vm-live-resize`, in the same session: the edge is held part way and then all the way, and the
|
|
neighbors' frames are read while the button is still down, and again after it is let go.
|