diff options
Diffstat (limited to 'src/ninep/ctl.zig')
| -rw-r--r-- | src/ninep/ctl.zig | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index dd2d9ed0..dd382290 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -473,11 +473,22 @@ pub fn writeRoot(p: *Pardes, req: Req) Reply { while (it.next()) |line| { if (line.len == 0) continue; if (std.mem.startsWith(u8, line, "size ") or std.mem.eql(u8, line, "size")) { - const size = sizeOf(line) orelse return refuse(p, req, "size takes <cols> <rows>", line); + const size = sizeOf(line) orelse return refuse(p, req, e_size, line); // A frontend's window is the size; only a session none is // attached to (--detach, unattended) takes one written. if (!p.unattended) return refuse(p, req, "size: a frontend is attached and owns the size", line); - if (apply) p.update(.{ .resize = .{ .cols = size[0], .rows = size[1] } }); + if (apply) { + const was: [2]u16 = .{ p.screen_w, p.screen_h }; + p.update(.{ .resize = .{ .cols = size[0], .rows = size[1] } }); + p.sync(); + // Every pane keeps its tag and two rows, as placement + // leaves them: a size too small for that is refused. + if (!pardes.layout.everyPaneRoomy(p)) { + p.update(.{ .resize = .{ .cols = was[0], .rows = was[1] } }); + p.sync(); + return refuse(p, req, "size: too small for the panes, each its tag and 2 rows", line); + } + } continue; } if (!apply) { @@ -493,12 +504,16 @@ pub fn writeRoot(p: *Pardes, req: Req) Reply { return .{ .tag = req.tag, .written = @intCast(req.data.len) }; } -/// `size <cols> <rows>`, each at least a few cells and at most 4096. +const size_min = [2]u16{ 20, 6 }; +const size_max = [2]u16{ 4096, 4096 }; +const e_size = std.fmt.comptimePrint("size takes <cols> <rows>, at least {d}x{d}, at most {d}x{d}", .{ size_min[0], size_min[1], size_max[0], size_max[1] }); + +/// `size <cols> <rows>`, within size_min and size_max. fn sizeOf(line: []const u8) ?[2]u16 { var it = std.mem.tokenizeAny(u8, line["size".len..], " \t"); const cols = std.fmt.parseInt(u16, it.next() orelse return null, 10) catch return null; const rows = std.fmt.parseInt(u16, it.next() orelse return null, 10) catch return null; - if (it.next() != null or cols < 20 or rows < 4 or cols > 4096 or rows > 4096) return null; + if (it.next() != null or cols < size_min[0] or rows < size_min[1] or cols > size_max[0] or rows > size_max[1]) return null; return .{ cols, rows }; } @@ -1490,5 +1505,12 @@ test "size sets the screen of a session no frontend is attached to, and only of try testing.expectEqual(@as(u16, 120), p.screen_w); try testing.expectEqual(@as(u16, 40), p.screen_h); try testing.expectEqual(E.INVAL, wr(p, root_ctl, "size 120\n").errno()); - try testing.expectEqual(E.INVAL, wr(p, root_ctl, "size 5 2\n").errno()); + try testing.expectEqual(E.INVAL, wr(p, root_ctl, "size\n").errno()); + try testing.expect(std.mem.indexOf(u8, wr(p, root_ctl, "size 5 2\n").reply.ename, "at least 20x6, at most 4096x4096") != null); + // Too small for the panes it has, each its tag and two rows: refused, + // the size as it was. + for (0..4) |_| p.newScratchBelow(p.active); + p.sync(); + try testing.expect(std.mem.indexOf(u8, wr(p, root_ctl, "size 80 8\n").reply.ename, "too small for the panes") != null); + try testing.expectEqual(@as(u16, 40), p.screen_h); } |
