use crate::*;
use crate::options_::*;
pub unsafe fn layout_create_cell(lcparent: *mut layout_cell) -> *mut layout_cell {
unsafe {
let lc = Box::leak(Box::new(layout_cell {
type_: layout_type::LAYOUT_WINDOWPANE,
flags: 0,
parent: lcparent,
sx: u32::MAX,
sy: u32::MAX,
xoff: u32::MAX,
yoff: u32::MAX,
wp: null_mut(),
cells: tailq_head {
tqh_first: null_mut(),
tqh_last: null_mut(),
},
entry: tailq_entry::default(),
}));
tailq_init(&raw mut lc.cells);
lc
}
}
pub unsafe fn layout_free_cell(lc: *mut layout_cell, only_nodes: c_int) {
unsafe {
if lc.is_null() || (only_nodes != 0 && (*lc).type_ == layout_type::LAYOUT_WINDOWPANE) {
return;
}
match (*lc).type_ {
layout_type::LAYOUT_LEFTRIGHT | layout_type::LAYOUT_TOPBOTTOM => {
let mut lcchild = tailq_first(&raw mut (*lc).cells);
while !lcchild.is_null() {
let lcnext = tailq_next(lcchild);
if only_nodes == 0 || (*lcchild).type_ != layout_type::LAYOUT_WINDOWPANE {
tailq_remove(&raw mut (*lc).cells, lcchild);
layout_free_cell(lcchild, only_nodes);
}
lcchild = lcnext;
}
}
layout_type::LAYOUT_WINDOWPANE => {
if !(*lc).wp.is_null() {
(*(*(*lc).wp).layout_cell).parent = null_mut();
(*(*lc).wp).layout_cell = null_mut();
}
}
}
free_(lc);
}
}
pub unsafe fn layout_cell_is_tiled(lc: *mut layout_cell) -> c_int {
unsafe {
let is_leaf = (*lc).type_ == layout_type::LAYOUT_WINDOWPANE;
let is_floating = (*lc).flags & LAYOUT_CELL_FLOATING != 0;
(is_leaf && !is_floating) as c_int
}
}
pub unsafe fn layout_print_cell(lc: *mut layout_cell, hdr: *const u8, n: u32) {
unsafe {
let type_str = match (*lc).type_ {
layout_type::LAYOUT_LEFTRIGHT => c"LEFTRIGHT",
layout_type::LAYOUT_TOPBOTTOM => c"TOPBOTTOM",
layout_type::LAYOUT_WINDOWPANE => c"WINDOWPANE",
};
log_debug!(
"{}:{}{:p} type {} [parent {:p}] wp={:p} [{},{} {}x{}]",
_s(hdr),
if n == 0 { "" } else { " " },
lc as *mut c_void,
type_str.to_string_lossy(),
(*lc).parent as *mut c_void,
(*lc).wp as *mut c_void,
(*lc).xoff,
(*lc).yoff,
(*lc).sx,
(*lc).sy,
);
match (*lc).type_ {
layout_type::LAYOUT_LEFTRIGHT | layout_type::LAYOUT_TOPBOTTOM => {
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
layout_print_cell(lcchild.as_ptr(), hdr, n + 1);
}
}
layout_type::LAYOUT_WINDOWPANE => (),
}
}
}
pub unsafe fn layout_search_by_border(lc: *mut layout_cell, x: u32, y: u32) -> *mut layout_cell {
unsafe {
let mut last: *mut layout_cell = null_mut();
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
let lcchild = lcchild.as_ptr();
if x >= (*lcchild).xoff
&& x < (*lcchild).xoff + (*lcchild).sx
&& y >= (*lcchild).yoff
&& y < (*lcchild).yoff + (*lcchild).sy
{
return layout_search_by_border(lcchild, x, y);
}
if last.is_null() {
last = lcchild;
continue;
}
match (*lc).type_ {
layout_type::LAYOUT_LEFTRIGHT => {
if x < (*lcchild).xoff && x >= (*last).xoff + (*last).sx {
return last;
}
}
layout_type::LAYOUT_TOPBOTTOM => {
if y < (*lcchild).yoff && y >= (*last).yoff + (*last).sy {
return last;
}
}
layout_type::LAYOUT_WINDOWPANE => (),
}
last = lcchild;
}
null_mut()
}
}
pub unsafe fn layout_set_size(lc: *mut layout_cell, sx: u32, sy: u32, xoff: u32, yoff: u32) {
unsafe {
(*lc).sx = sx;
(*lc).sy = sy;
(*lc).xoff = xoff;
(*lc).yoff = yoff;
}
}
pub unsafe fn layout_make_leaf(lc: *mut layout_cell, wp: *mut window_pane) {
unsafe {
(*lc).type_ = layout_type::LAYOUT_WINDOWPANE;
tailq_init(&raw mut (*lc).cells);
(*wp).layout_cell = lc;
(*lc).wp = wp;
}
}
pub unsafe fn layout_make_node(lc: *mut layout_cell, type_: layout_type) {
unsafe {
if type_ == layout_type::LAYOUT_WINDOWPANE {
fatalx("bad layout type");
}
(*lc).type_ = type_;
tailq_init(&raw mut (*lc).cells);
if !(*lc).wp.is_null() {
(*(*lc).wp).layout_cell = null_mut();
}
(*lc).wp = null_mut();
}
}
unsafe fn layout_fix_offsets1(lc: *mut layout_cell) {
unsafe {
if (*lc).type_ == layout_type::LAYOUT_LEFTRIGHT {
let mut xoff = (*lc).xoff;
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
let lcchild = lcchild.as_ptr();
(*lcchild).xoff = xoff;
(*lcchild).yoff = (*lc).yoff;
if (*lcchild).type_ != layout_type::LAYOUT_WINDOWPANE {
layout_fix_offsets1(lcchild);
}
xoff += (*lcchild).sx + 1;
}
} else {
let mut yoff = (*lc).yoff;
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
let lcchild = lcchild.as_ptr();
(*lcchild).xoff = (*lc).xoff;
(*lcchild).yoff = yoff;
if (*lcchild).type_ != layout_type::LAYOUT_WINDOWPANE {
layout_fix_offsets1(lcchild);
}
yoff += (*lcchild).sy + 1;
}
}
}
}
pub unsafe fn layout_fix_offsets(w: *mut window) {
unsafe {
let lc = (*w).layout_root;
(*lc).xoff = 0;
(*lc).yoff = 0;
layout_fix_offsets1(lc);
}
}
unsafe fn layout_cell_is_top(w: *mut window, mut lc: *mut layout_cell) -> c_int {
unsafe {
while lc != (*w).layout_root {
let next = (*lc).parent;
if (*next).type_ == layout_type::LAYOUT_TOPBOTTOM
&& lc != tailq_first(&raw mut (*next).cells)
{
return 0;
}
lc = next;
}
1
}
}
unsafe fn layout_cell_is_bottom(w: *mut window, mut lc: *mut layout_cell) -> c_int {
unsafe {
while lc != (*w).layout_root {
let next = (*lc).parent;
if (*next).type_ == layout_type::LAYOUT_TOPBOTTOM
&& lc != tailq_last(&raw mut (*next).cells)
{
return 0;
}
lc = next;
}
1
}
}
unsafe fn layout_add_border(w: *mut window, lc: *mut layout_cell, status: pane_status) -> bool {
unsafe {
if status == pane_status::PANE_STATUS_TOP {
return layout_cell_is_top(w, lc) != 0;
}
if status == pane_status::PANE_STATUS_BOTTOM {
return layout_cell_is_bottom(w, lc) != 0;
}
false
}
}
pub unsafe fn layout_fix_panes(w: *mut window, skip: *mut window_pane) {
unsafe {
let status: pane_status =
pane_status::try_from(options_get_number_((*w).options, "pane-border-status") as i32)
.unwrap();
for wp in tailq_foreach::<window_pane, discr_entry>(&raw mut (*w).panes) {
let wp = wp.as_ptr();
let lc = (*wp).layout_cell;
if lc.is_null() || wp == skip {
continue;
}
(*wp).xoff = (*lc).xoff;
(*wp).yoff = (*lc).yoff;
if layout_add_border(w, lc, status) {
if status == pane_status::PANE_STATUS_TOP {
(*wp).yoff += 1;
}
window_pane_resize(wp, (*lc).sx, (*lc).sy - 1);
} else {
window_pane_resize(wp, (*lc).sx, (*lc).sy);
}
}
}
}
pub unsafe fn layout_count_cells(lc: *mut layout_cell) -> u32 {
unsafe {
match (*lc).type_ {
layout_type::LAYOUT_WINDOWPANE => 1,
layout_type::LAYOUT_LEFTRIGHT | layout_type::LAYOUT_TOPBOTTOM => {
let mut count = 0;
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
count += layout_count_cells(lcchild.as_ptr());
}
count
}
}
}
}
pub unsafe fn layout_resize_check(w: *mut window, lc: *mut layout_cell, type_: layout_type) -> u32 {
unsafe {
let mut available: u32;
let mut minimum: u32;
let status: pane_status =
pane_status::try_from(options_get_number_((*w).options, "pane-border-status") as i32)
.unwrap();
if (*lc).type_ == layout_type::LAYOUT_WINDOWPANE {
if type_ == layout_type::LAYOUT_LEFTRIGHT {
available = (*lc).sx;
minimum = PANE_MINIMUM;
} else {
available = (*lc).sy;
if layout_add_border(w, lc, status) {
minimum = PANE_MINIMUM + 1;
} else {
minimum = PANE_MINIMUM;
}
}
if available > minimum {
available -= minimum;
} else {
available = 0;
}
} else if (*lc).type_ == type_ {
available = 0;
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
available += layout_resize_check(w, lcchild.as_ptr(), type_);
}
} else {
minimum = u32::MAX;
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
available = layout_resize_check(w, lcchild.as_ptr(), type_);
if available < minimum {
minimum = available;
}
}
available = minimum;
}
available
}
}
pub unsafe fn layout_resize_adjust(
w: *mut window,
lc: *mut layout_cell,
type_: layout_type,
mut change: i32,
) {
unsafe {
if type_ == layout_type::LAYOUT_LEFTRIGHT {
(*lc).sx = ((*lc).sx as i32 + change) as u32;
} else {
(*lc).sy = ((*lc).sy as i32 + change) as u32;
}
if (*lc).type_ == layout_type::LAYOUT_WINDOWPANE {
return;
}
if (*lc).type_ != type_ {
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
layout_resize_adjust(w, lcchild.as_ptr(), type_, change);
}
return;
}
while change != 0 {
for lcchild in tailq_foreach(&raw mut (*lc).cells) {
if change == 0 {
break;
}
if change > 0 {
layout_resize_adjust(w, lcchild.as_ptr(), type_, 1);
change -= 1;
continue;
}
if layout_resize_check(w, lcchild.as_ptr(), type_) > 0 {
layout_resize_adjust(w, lcchild.as_ptr(), type_, -1);
change += 1;
}
}
}
}
}
pub unsafe fn layout_destroy_cell(
w: *mut window,
lc: *mut layout_cell,
lcroot: *mut *mut layout_cell,
) {
unsafe {
let lcparent = (*lc).parent;
if lcparent.is_null() {
layout_free_cell(lc, 0);
*lcroot = std::ptr::null_mut();
return;
}
let lcother: *mut layout_cell = if lc == tailq_first(&raw mut (*lcparent).cells) {
tailq_next(lc)
} else {
tailq_prev(lc)
};
if !lcother.is_null() {
if (*lcparent).type_ == layout_type::LAYOUT_LEFTRIGHT {
layout_resize_adjust(w, lcother, (*lcparent).type_, (*lc).sx as i32 + 1);
} else {
layout_resize_adjust(w, lcother, (*lcparent).type_, (*lc).sy as i32 + 1);
}
}
tailq_remove(&mut (*lcparent).cells, lc);
layout_free_cell(lc, 0);
let lc = tailq_first(&raw mut (*lcparent).cells);
if tailq_next(lc).is_null() {
tailq_remove(&raw mut (*lcparent).cells, lc);
(*lc).parent = (*lcparent).parent;
if (*lc).parent.is_null() {
(*lc).xoff = 0;
(*lc).yoff = 0;
*lcroot = lc;
} else {
tailq_replace(&mut (*(*lc).parent).cells, lcparent, lc);
}
layout_free_cell(lcparent, 0);
}
}
}
pub unsafe fn layout_init(w: *mut window, wp: *mut window_pane) {
unsafe {
let lc = layout_create_cell(std::ptr::null_mut());
(*w).layout_root = lc;
layout_set_size(lc, (*w).sx, (*w).sy, 0, 0);
layout_make_leaf(lc, wp);
layout_fix_panes(w, std::ptr::null_mut());
}
}
pub unsafe fn layout_free(w: *mut window, only_nodes: c_int) {
unsafe {
layout_free_cell((*w).layout_root, only_nodes);
}
}
pub unsafe fn layout_resize(w: *mut window, sx: c_uint, sy: c_uint) {
unsafe {
let lc = (*w).layout_root;
let mut xchange = sx as c_int - (*lc).sx as c_int;
let xlimit = layout_resize_check(w, lc, layout_type::LAYOUT_LEFTRIGHT) as i32;
if xchange < 0 && xchange < -xlimit {
xchange = -xlimit;
}
if xlimit == 0 {
if sx <= (*lc).sx {
xchange = 0;
} else {
xchange = sx as c_int - (*lc).sx as c_int;
}
}
if xchange != 0 {
layout_resize_adjust(w, lc, layout_type::LAYOUT_LEFTRIGHT, xchange);
}
let mut ychange = sy as c_int - (*lc).sy as c_int;
let ylimit = layout_resize_check(w, lc, layout_type::LAYOUT_TOPBOTTOM) as i32;
if ychange < 0 && ychange < -ylimit {
ychange = -ylimit;
}
if ylimit == 0 {
if sy <= (*lc).sy {
ychange = 0;
} else {
ychange = sy as c_int - (*lc).sy as c_int;
}
}
if ychange != 0 {
layout_resize_adjust(w, lc, layout_type::LAYOUT_TOPBOTTOM, ychange);
}
layout_fix_offsets(w);
layout_fix_panes(w, std::ptr::null_mut());
}
}
pub unsafe fn layout_resize_pane_to(wp: *mut window_pane, type_: layout_type, new_size: u32) {
unsafe {
let mut lc = (*wp).layout_cell;
let mut lcparent;
lcparent = (*lc).parent;
while !lcparent.is_null() && (*lcparent).type_ != type_ {
lc = lcparent;
lcparent = (*lc).parent;
}
if lcparent.is_null() {
return;
}
let size = if type_ == layout_type::LAYOUT_LEFTRIGHT {
(*lc).sx
} else {
(*lc).sy
};
let change = if lc == tailq_last(&raw mut (*lcparent).cells) {
size as i32 - new_size as i32
} else {
new_size as i32 - size as i32
};
layout_resize_pane(wp, type_, change, 1);
}
}
pub unsafe fn layout_resize_layout(
w: *mut window,
lc: *mut layout_cell,
type_: layout_type,
change: c_int,
opposite: c_int,
) {
unsafe {
let mut needed = change;
let mut size;
while needed != 0 {
if change > 0 {
size = layout_resize_pane_grow(w, lc, type_, needed, opposite);
needed -= size;
} else {
size = layout_resize_pane_shrink(w, lc, type_, needed);
needed += size;
}
if size == 0 {
break;
}
}
layout_fix_offsets(w);
layout_fix_panes(w, null_mut());
notify_window(c"window-layout-changed", w);
}
}
pub unsafe fn layout_resize_pane(
wp: *mut window_pane,
type_: layout_type,
change: c_int,
opposite: c_int,
) {
unsafe {
let mut lc = (*wp).layout_cell;
let mut lcparent;
lcparent = (*lc).parent;
while !lcparent.is_null() && (*lcparent).type_ != type_ {
lc = lcparent;
lcparent = (*lc).parent;
}
if lcparent.is_null() {
return;
}
if lc == tailq_last(&raw mut (*lcparent).cells) {
lc = tailq_prev(lc);
}
layout_resize_layout((*wp).window, lc, type_, change, opposite);
}
}
pub unsafe fn layout_resize_pane_grow(
w: *mut window,
lc: *mut layout_cell,
type_: layout_type,
needed: c_int,
opposite: c_int,
) -> c_int {
unsafe {
let mut size: u32 = 0;
let lcadd = lc;
let mut lcremove = tailq_next(lc);
while !lcremove.is_null() {
size = layout_resize_check(w, lcremove, type_);
if size > 0 {
break;
}
lcremove = tailq_next(lcremove);
}
if opposite != 0 && lcremove.is_null() {
lcremove = tailq_prev(lc);
while !lcremove.is_null() {
size = layout_resize_check(w, lcremove, type_);
if size > 0 {
break;
}
lcremove = tailq_prev(lcremove);
}
}
if lcremove.is_null() {
return 0;
}
if size > needed as u32 {
size = needed as u32;
}
layout_resize_adjust(w, lcadd, type_, size as c_int);
layout_resize_adjust(w, lcremove, type_, -(size as c_int));
size as c_int
}
}
pub unsafe fn layout_resize_pane_shrink(
w: *mut window,
lc: *mut layout_cell,
type_: layout_type,
needed: c_int,
) -> c_int {
unsafe {
let mut size: u32;
let mut lcremove = lc;
loop {
size = layout_resize_check(w, lcremove, type_);
if size != 0 {
break;
}
lcremove = tailq_prev(lcremove);
if lcremove.is_null() {
break;
}
}
if lcremove.is_null() {
return 0;
}
let lcadd = tailq_next(lc);
if lcadd.is_null() {
return 0;
}
if size > (-needed) as u32 {
size = (-needed) as u32;
}
layout_resize_adjust(w, lcadd, type_, size as c_int);
layout_resize_adjust(w, lcremove, type_, -(size as c_int));
size as c_int
}
}
pub unsafe fn layout_assign_pane(lc: *mut layout_cell, wp: *mut window_pane, do_not_resize: c_int) {
unsafe {
layout_make_leaf(lc, wp);
if do_not_resize != 0 {
layout_fix_panes((*wp).window, wp);
} else {
layout_fix_panes((*wp).window, null_mut());
}
}
}
pub unsafe fn layout_new_pane_size(
w: *mut window,
previous: u32,
lc: *mut layout_cell,
type_: layout_type,
size: u32,
count_left: u32,
size_left: u32,
) -> u32 {
unsafe {
if count_left == 1 {
return size_left;
}
let available: u32 = layout_resize_check(w, lc, type_);
let mut min: u32 = (PANE_MINIMUM + 1) * (count_left - 1);
let mut new_size: u32 = if type_ == layout_type::LAYOUT_LEFTRIGHT {
if (*lc).sx - available > min {
min = (*lc).sx - available;
}
((*lc).sx * size) / previous
} else {
if (*lc).sy - available > min {
min = (*lc).sy - available;
}
((*lc).sy * size) / previous
};
let max: u32 = size_left - min;
if new_size > max {
new_size = max;
}
if new_size < PANE_MINIMUM {
new_size = PANE_MINIMUM;
}
new_size
}
}
pub unsafe fn layout_set_size_check(
w: *mut window,
lc: *mut layout_cell,
type_: layout_type,
size: c_int,
) -> bool {
unsafe {
let mut new_size: u32;
let mut available: u32;
let previous: u32;
let mut idx: u32;
if (*lc).type_ == layout_type::LAYOUT_WINDOWPANE {
return size >= PANE_MINIMUM as i32;
}
available = size as u32;
let count: u32 = tailq_foreach(&raw mut (*lc).cells).count() as u32;
if (*lc).type_ == type_ {
if available < (count * 2) - 1 {
return false;
}
if type_ == layout_type::LAYOUT_LEFTRIGHT {
previous = (*lc).sx;
} else {
previous = (*lc).sy;
}
idx = 0;
for lcchild in tailq_foreach(&raw mut (*lc).cells).map(NonNull::as_ptr) {
new_size = layout_new_pane_size(
w,
previous,
lcchild,
type_,
size as u32,
count - idx,
available,
);
if idx == count - 1 {
if new_size > available {
return false;
}
available -= new_size;
} else {
if new_size + 1 > available {
return false;
}
available -= new_size + 1;
}
if !layout_set_size_check(w, lcchild, type_, new_size as i32) {
return false;
}
idx += 1;
}
} else {
for lcchild in tailq_foreach(&raw mut (*lc).cells).map(NonNull::as_ptr) {
if (*lcchild).type_ == layout_type::LAYOUT_WINDOWPANE {
continue;
}
if !layout_set_size_check(w, lcchild, type_, size) {
return false;
}
}
}
true
}
}
pub unsafe fn layout_resize_child_cells(w: *mut window, lc: *mut layout_cell) {
unsafe {
if (*lc).type_ == layout_type::LAYOUT_WINDOWPANE {
return;
}
let mut count: u32 = 0;
let mut previous: u32 = 0;
for lcchild in tailq_foreach(&raw mut (*lc).cells).map(NonNull::as_ptr) {
count += 1;
if (*lc).type_ == layout_type::LAYOUT_LEFTRIGHT {
previous += (*lcchild).sx;
} else if (*lc).type_ == layout_type::LAYOUT_TOPBOTTOM {
previous += (*lcchild).sy;
}
}
previous += count - 1;
let mut available: u32 = 0;
if (*lc).type_ == layout_type::LAYOUT_LEFTRIGHT {
available = (*lc).sx;
} else if (*lc).type_ == layout_type::LAYOUT_TOPBOTTOM {
available = (*lc).sy;
}
for (idx, lcchild) in tailq_foreach(&raw mut (*lc).cells)
.map(NonNull::as_ptr)
.enumerate()
{
if (*lc).type_ == layout_type::LAYOUT_TOPBOTTOM {
(*lcchild).sx = (*lc).sx;
(*lcchild).xoff = (*lc).xoff;
} else {
(*lcchild).sx = layout_new_pane_size(
w,
previous,
lcchild,
(*lc).type_,
(*lc).sx,
count - idx as u32,
available,
);
available -= (*lcchild).sx + 1;
}
if (*lc).type_ == layout_type::LAYOUT_LEFTRIGHT {
(*lcchild).sy = (*lc).sy;
} else {
(*lcchild).sy = layout_new_pane_size(
w,
previous,
lcchild,
(*lc).type_,
(*lc).sy,
count - idx as u32,
available,
);
available -= (*lcchild).sy + 1;
}
layout_resize_child_cells(w, lcchild);
}
}
}
pub unsafe fn layout_replace_with_node(
w: *mut window,
lc: *mut layout_cell,
type_: layout_type,
) -> *mut layout_cell {
unsafe {
let lcparent = layout_create_cell((*lc).parent);
layout_make_node(lcparent, type_);
layout_set_size(lcparent, (*lc).sx, (*lc).sy, (*lc).xoff, (*lc).yoff);
if (*lc).parent.is_null() {
(*w).layout_root = lcparent;
} else {
tailq_replace(&raw mut (*(*lc).parent).cells, lc, lcparent);
}
(*lc).parent = lcparent;
tailq_insert_head(&raw mut (*lcparent).cells, lc);
lcparent
}
}
pub unsafe fn layout_floating_pane(
w: *mut window,
wp: *mut window_pane,
sx: u32,
sy: u32,
ox: c_int,
oy: c_int,
) -> *mut layout_cell {
unsafe {
let lc = if wp.is_null() {
(*w).layout_root
} else {
(*wp).layout_cell
};
let mut lcparent = (*lc).parent;
if lcparent.is_null() {
lcparent = layout_replace_with_node(w, lc, layout_type::LAYOUT_TOPBOTTOM);
}
let lcnew = layout_create_cell(lcparent);
tailq_insert_after(&raw mut (*lcparent).cells, lc, lcnew);
(*lcnew).flags |= LAYOUT_CELL_FLOATING;
layout_set_size(lcnew, sx, sy, ox as u32, oy as u32);
lcnew
}
}
pub unsafe fn layout_floating_args_parse(
item: *mut cmdq_item,
args: *mut args,
lines: pane_lines,
w: *mut window,
sxp: *mut u32,
syp: *mut u32,
oxp: *mut c_int,
oyp: *mut c_int,
cause: *mut *mut u8,
) -> c_int {
unsafe {
let mut error: *mut u8 = null_mut();
let mut sx: c_int = if *sxp == u32::MAX {
((*w).sx / 2) as c_int
} else {
*sxp as c_int
};
let mut sy: c_int = if *syp == u32::MAX {
((*w).sy / 4) as c_int
} else {
*syp as c_int
};
let mut ox: c_int = if *oxp == c_int::MAX { c_int::MAX } else { *oxp };
let mut oy: c_int = if *oyp == c_int::MAX { c_int::MAX } else { *oyp };
if args_has(args, 'x') {
sx = args_percentage_and_expand(
args, b'x', 0, PANE_MAXIMUM as i64, (*w).sx as i64, item, &raw mut error,
) as c_int;
if !error.is_null() {
*cause = format_nul!("position {}", _s(error));
free_(error);
return -1;
}
if lines != pane_lines::PANE_LINES_NONE {
sx -= 2;
}
}
if args_has(args, 'y') {
sy = args_percentage_and_expand(
args, b'y', 0, PANE_MAXIMUM as i64, (*w).sy as i64, item, &raw mut error,
) as c_int;
if !error.is_null() {
*cause = format_nul!("position {}", _s(error));
free_(error);
return -1;
}
if lines != pane_lines::PANE_LINES_NONE {
sy -= 2;
}
}
if args_has(args, 'X') {
ox = args_percentage_and_expand(
args, b'X', (-sx) as i64, (*w).sx as i64, (*w).sx as i64, item, &raw mut error,
) as c_int;
if !error.is_null() {
*cause = format_nul!("position {}", _s(error));
free_(error);
return -1;
}
}
if args_has(args, 'Y') {
oy = args_percentage_and_expand(
args, b'Y', (-sy) as i64, (*w).sy as i64, (*w).sy as i64, item, &raw mut error,
) as c_int;
if !error.is_null() {
*cause = format_nul!("position {}", _s(error));
free_(error);
return -1;
}
}
if ox == c_int::MAX {
if (*w).last_new_pane_x == 0 {
ox = 4;
} else {
ox = (*w).last_new_pane_x as c_int + 4;
if (*w).last_new_pane_x > (*w).sx {
ox = 4;
}
}
(*w).last_new_pane_x = ox as u32;
} else if lines != pane_lines::PANE_LINES_NONE {
ox += 1;
}
if oy == c_int::MAX {
if (*w).last_new_pane_y == 0 {
oy = 2;
} else {
oy = (*w).last_new_pane_y as c_int + 2;
if (*w).last_new_pane_y > (*w).sy {
oy = 2;
}
}
(*w).last_new_pane_y = oy as u32;
} else if lines != pane_lines::PANE_LINES_NONE {
oy += 1;
}
if sx < PANE_MINIMUM as c_int || sx > PANE_MAXIMUM as c_int {
*cause = xstrdup(c!("invalid width")).as_ptr();
return -1;
}
if sy < PANE_MINIMUM as c_int || sy > PANE_MAXIMUM as c_int {
*cause = xstrdup(c!("invalid height")).as_ptr();
return -1;
}
*sxp = sx as u32;
*syp = sy as u32;
*oxp = ox;
*oyp = oy;
0
}
}
pub unsafe fn layout_get_floating_cell(
item: *mut cmdq_item,
args: *mut args,
lines: pane_lines,
w: *mut window,
wp: *mut window_pane,
cause: *mut *mut u8,
) -> *mut layout_cell {
unsafe {
let mut sx: u32 = u32::MAX;
let mut sy: u32 = u32::MAX;
let mut ox: c_int = c_int::MAX;
let mut oy: c_int = c_int::MAX;
if layout_floating_args_parse(
item, args, lines, w, &raw mut sx, &raw mut sy, &raw mut ox, &raw mut oy, cause,
) != 0
{
return null_mut();
}
layout_floating_pane(w, wp, sx, sy, ox, oy)
}
}
pub unsafe fn layout_split_pane(
wp: *mut window_pane,
type_: layout_type,
size: i32,
flags: spawn_flags,
) -> *mut layout_cell {
unsafe {
let minimum: u32;
let mut resize_first: u32 = 0;
let full_size = flags.intersects(SPAWN_FULLSIZE);
let lc: *mut layout_cell = if full_size {
(*(*wp).window).layout_root
} else {
(*wp).layout_cell
};
let status = pane_status::try_from(options_get_number_(
(*(*wp).window).options,
"pane-border-status",
) as i32)
.unwrap();
let sx = (*lc).sx;
let sy = (*lc).sy;
let xoff = (*lc).xoff;
let yoff = (*lc).yoff;
match type_ {
layout_type::LAYOUT_LEFTRIGHT => {
if sx < PANE_MINIMUM * 2 + 1 {
return null_mut();
}
}
layout_type::LAYOUT_TOPBOTTOM => {
if layout_add_border((*wp).window, lc, status) {
minimum = PANE_MINIMUM * 2 + 2;
} else {
minimum = PANE_MINIMUM * 2 + 1;
}
if sy < minimum {
return null_mut();
}
}
_ => fatalx("bad layout type"),
}
let saved_size = if type_ == layout_type::LAYOUT_LEFTRIGHT {
sx
} else {
sy
};
let mut size2 = if size < 0 {
saved_size.div_ceil(2) - 1
} else if flags.intersects(SPAWN_BEFORE) {
saved_size - size as u32 - 1
} else {
size as u32
};
if size2 < PANE_MINIMUM {
size2 = PANE_MINIMUM;
} else if size2 > saved_size - 2 {
size2 = saved_size - 2;
}
let size1 = saved_size - 1 - size2;
let new_size = if flags.intersects(SPAWN_BEFORE) {
size2
} else {
size1
};
if full_size && !layout_set_size_check((*wp).window, lc, type_, new_size as i32) {
return null_mut();
}
let lcparent: *mut layout_cell;
let lcnew: *mut layout_cell;
if !(*lc).parent.is_null() && (*(*lc).parent).type_ == type_ {
lcparent = (*lc).parent;
lcnew = layout_create_cell(lcparent);
if flags.intersects(SPAWN_BEFORE) {
tailq_insert_before(lc, lcnew);
} else {
tailq_insert_after(&raw mut (*lcparent).cells, lc, lcnew);
}
} else if full_size && (*lc).parent.is_null() && (*lc).type_ == type_ {
if (*lc).type_ == layout_type::LAYOUT_LEFTRIGHT {
(*lc).sx = new_size;
layout_resize_child_cells((*wp).window, lc);
(*lc).sx = saved_size;
} else if (*lc).type_ == layout_type::LAYOUT_TOPBOTTOM {
(*lc).sy = new_size;
layout_resize_child_cells((*wp).window, lc);
(*lc).sy = saved_size;
}
resize_first = 1;
lcnew = layout_create_cell(lc);
let size = saved_size - 1 - new_size;
if (*lc).type_ == layout_type::LAYOUT_LEFTRIGHT {
layout_set_size(lcnew, size, sy, 0, 0);
} else if (*lc).type_ == layout_type::LAYOUT_TOPBOTTOM {
layout_set_size(lcnew, sx, size, 0, 0);
}
if flags.intersects(SPAWN_BEFORE) {
tailq_insert_head(&raw mut (*lc).cells, lcnew);
} else {
tailq_insert_tail(&raw mut (*lc).cells, lcnew);
}
} else {
lcparent = layout_create_cell((*lc).parent);
layout_make_node(lcparent, type_);
layout_set_size(lcparent, sx, sy, xoff, yoff);
if (*lc).parent.is_null() {
(*(*wp).window).layout_root = lcparent;
} else {
tailq_replace(&raw mut (*(*lc).parent).cells, lc, lcparent);
}
(*lc).parent = lcparent;
tailq_insert_head(&raw mut (*lcparent).cells, lc);
lcnew = layout_create_cell(lcparent);
if flags.intersects(SPAWN_BEFORE) {
tailq_insert_head(&raw mut (*lcparent).cells, lcnew);
} else {
tailq_insert_tail(&raw mut (*lcparent).cells, lcnew);
}
}
let (lc1, lc2) = if flags.intersects(SPAWN_BEFORE) {
(lcnew, lc)
} else {
(lc, lcnew)
};
if resize_first == 0 && type_ == layout_type::LAYOUT_LEFTRIGHT {
layout_set_size(lc1, size1, sy, xoff, yoff);
layout_set_size(lc2, size2, sy, xoff + (*lc1).sx + 1, yoff);
} else if resize_first == 0 && type_ == layout_type::LAYOUT_TOPBOTTOM {
layout_set_size(lc1, sx, size1, xoff, yoff);
layout_set_size(lc2, sx, size2, xoff, yoff + (*lc1).sy + 1);
}
if full_size {
if resize_first == 0 {
layout_resize_child_cells((*wp).window, lc);
}
layout_fix_offsets((*wp).window);
} else {
layout_make_leaf(lc, wp);
}
lcnew
}
}
pub unsafe fn layout_close_pane(wp: *mut window_pane) {
unsafe {
let w = (*wp).window;
layout_destroy_cell(w, (*wp).layout_cell, &raw mut (*w).layout_root);
if !(*w).layout_root.is_null() {
layout_fix_offsets(w);
layout_fix_panes(w, null_mut());
}
notify_window(c"window-layout-changed", w);
}
}
pub unsafe fn layout_spread_cell(w: *mut window, parent: *mut layout_cell) -> c_int {
unsafe {
let number = tailq_foreach(&raw mut (*parent).cells).count() as u32;
if number <= 1 {
return 0;
}
let status: pane_status = (options_get_number_((*w).options, "pane-border-status") as i32)
.try_into()
.unwrap();
let size = match (*parent).type_ {
layout_type::LAYOUT_LEFTRIGHT => (*parent).sx,
layout_type::LAYOUT_TOPBOTTOM => {
if layout_add_border(w, parent, status) {
(*parent).sy - 1
} else {
(*parent).sy
}
}
_ => return 0,
};
if size < number - 1 {
return 0;
}
let each = (size - (number - 1)) / number;
if each == 0 {
return 0;
}
let mut remainder = size
.wrapping_sub(number.wrapping_mul(each + 1))
.wrapping_add(1);
let mut changed = 0;
for lc in tailq_foreach(&raw mut (*parent).cells).map(NonNull::as_ptr) {
let change = match (*parent).type_ {
layout_type::LAYOUT_LEFTRIGHT => {
let mut change = each as i32 - (*lc).sx as i32;
if remainder > 0 {
change += 1;
remainder -= 1;
}
layout_resize_adjust(w, lc, layout_type::LAYOUT_LEFTRIGHT, change);
change
}
layout_type::LAYOUT_TOPBOTTOM => {
let mut this = if layout_add_border(w, lc, status) {
each + 1
} else {
each
};
if remainder > 0 {
this += 1;
remainder -= 1;
}
let change = this as i32 - (*lc).sy as i32;
layout_resize_adjust(w, lc, layout_type::LAYOUT_TOPBOTTOM, change);
change
}
_ => 0,
};
if change != 0 {
changed = 1;
}
}
changed
}
}
pub unsafe fn layout_spread_out(wp: *mut window_pane) {
unsafe {
let mut parent = (*wp).layout_cell;
if parent.is_null() {
return;
}
parent = (*parent).parent;
if parent.is_null() {
return;
}
let w = (*wp).window;
while !parent.is_null() {
if layout_spread_cell(w, parent) != 0 {
layout_fix_offsets(w);
layout_fix_panes(w, null_mut());
break;
}
parent = (*parent).parent;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
unsafe fn leaf(sx: u32, sy: u32) -> *mut layout_cell {
unsafe {
let lc = layout_create_cell(null_mut());
(*lc).type_ = layout_type::LAYOUT_WINDOWPANE;
(*lc).sx = sx;
(*lc).sy = sy;
(*lc).xoff = 0;
(*lc).yoff = 0;
lc
}
}
unsafe fn node(type_: layout_type, children: &[*mut layout_cell]) -> *mut layout_cell {
unsafe {
let p = layout_create_cell(null_mut());
(*p).type_ = type_;
(*p).sx = 0;
(*p).sy = 0;
(*p).xoff = 0;
(*p).yoff = 0;
for &c in children {
(*c).parent = p;
tailq_insert_tail(&raw mut (*p).cells, c);
}
p
}
}
#[test]
fn create_cell_defaults() {
unsafe {
let lc = layout_create_cell(null_mut());
assert!((*lc).type_ == layout_type::LAYOUT_WINDOWPANE);
assert!((*lc).parent.is_null());
assert!((*lc).wp.is_null());
assert_eq!((*lc).sx, u32::MAX);
assert_eq!((*lc).sy, u32::MAX);
assert!(tailq_empty(&raw mut (*lc).cells));
layout_free_cell(lc, 0);
}
}
#[test]
fn count_cells_recurses() {
unsafe {
let inner = node(layout_type::LAYOUT_TOPBOTTOM, &[leaf(10, 5), leaf(10, 5)]);
let root = node(layout_type::LAYOUT_LEFTRIGHT, &[leaf(20, 10), inner]);
assert_eq!(layout_count_cells(root), 3);
layout_free_cell(root, 0);
}
}
#[test]
fn resize_adjust_leaf_touches_only_its_axis() {
unsafe {
let lc = leaf(40, 24);
layout_resize_adjust(null_mut(), lc, layout_type::LAYOUT_LEFTRIGHT, 5);
assert_eq!((*lc).sx, 45);
assert_eq!((*lc).sy, 24);
layout_resize_adjust(null_mut(), lc, layout_type::LAYOUT_TOPBOTTOM, -4);
assert_eq!((*lc).sx, 45);
assert_eq!((*lc).sy, 20);
layout_free_cell(lc, 0);
}
}
#[test]
fn resize_adjust_grows_children_equally() {
unsafe {
let a = leaf(40, 24);
let b = leaf(40, 24);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
(*p).sx = 81;
layout_resize_adjust(null_mut(), p, layout_type::LAYOUT_LEFTRIGHT, 3);
assert_eq!((*a).sx, 42);
assert_eq!((*b).sx, 41);
layout_free_cell(p, 0);
}
}
#[test]
fn fix_offsets_lays_cells_left_to_right() {
unsafe {
let a = leaf(40, 24);
let b = leaf(39, 24);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
(*p).xoff = 0;
(*p).yoff = 0;
layout_fix_offsets1(p);
assert_eq!(((*a).xoff, (*a).yoff), (0, 0));
assert_eq!(((*b).xoff, (*b).yoff), (41, 0));
layout_free_cell(p, 0);
}
}
#[test]
fn fix_offsets_stacks_cells_top_to_bottom() {
unsafe {
let a = leaf(80, 12);
let b = leaf(80, 11);
let p = node(layout_type::LAYOUT_TOPBOTTOM, &[a, b]);
layout_fix_offsets1(p);
assert_eq!(((*a).xoff, (*a).yoff), (0, 0));
assert_eq!(((*b).xoff, (*b).yoff), (0, 13));
layout_free_cell(p, 0);
}
}
#[test]
fn search_by_border_finds_the_divider() {
unsafe {
let a = leaf(40, 24);
let b = leaf(40, 24);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
(*p).xoff = 0;
(*p).yoff = 0;
layout_fix_offsets1(p);
assert!(layout_search_by_border(p, 10, 5).is_null());
assert_eq!(layout_search_by_border(p, 40, 5), a);
layout_free_cell(p, 0);
}
}
fn spread_sizes(size: u32, number: u32) -> Vec<u32> {
let each = (size - (number - 1)) / number;
let mut remainder = size
.wrapping_sub(number.wrapping_mul(each + 1))
.wrapping_add(1);
(0..number)
.map(|_| {
let mut this = each;
if remainder > 0 {
this += 1;
remainder -= 1;
}
this
})
.collect()
}
#[test]
fn spread_remainder_goes_to_leading_cells() {
assert_eq!(spread_sizes(80, 2), vec![40, 39]);
assert_eq!(spread_sizes(80, 3), vec![26, 26, 26]);
for size in [10u32, 24, 80, 100, 200] {
for number in 2u32..=6 {
if size < number - 1 {
continue;
}
let sizes = spread_sizes(size, number);
let sum: u32 = sizes.iter().sum();
assert_eq!(sum + (number - 1), size, "size {size} n {number}");
for w in sizes.windows(2) {
assert!(w[0] >= w[1], "size {size} n {number}: {sizes:?}");
}
}
}
}
#[test]
fn spread_via_resize_adjust_yields_40_39() {
unsafe {
let a = leaf(0, 24);
let b = leaf(0, 24);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
let size = 80u32;
let sizes = spread_sizes(size, 2);
for (lc, &want) in [a, b].iter().zip(sizes.iter()) {
let change = want as i32 - (**lc).sx as i32;
layout_resize_adjust(null_mut(), *lc, layout_type::LAYOUT_LEFTRIGHT, change);
}
assert_eq!((*a).sx, 40);
assert_eq!((*b).sx, 39);
layout_free_cell(p, 0);
}
}
#[test]
fn set_size_sets_all_four_fields() {
unsafe {
let lc = leaf(1, 1);
layout_set_size(lc, 80, 24, 3, 7);
assert_eq!((*lc).sx, 80);
assert_eq!((*lc).sy, 24);
assert_eq!((*lc).xoff, 3);
assert_eq!((*lc).yoff, 7);
layout_free_cell(lc, 0);
}
}
#[test]
fn make_node_converts_leaf_and_reinits_cells() {
unsafe {
let lc = leaf(40, 24);
assert!((*lc).type_ == layout_type::LAYOUT_WINDOWPANE);
layout_make_node(lc, layout_type::LAYOUT_LEFTRIGHT);
assert!((*lc).type_ == layout_type::LAYOUT_LEFTRIGHT);
assert!((*lc).wp.is_null());
assert!(tailq_empty(&raw mut (*lc).cells));
layout_make_node(lc, layout_type::LAYOUT_TOPBOTTOM);
assert!((*lc).type_ == layout_type::LAYOUT_TOPBOTTOM);
layout_free_cell(lc, 0);
}
}
#[test]
fn make_leaf_wires_pane_then_make_node_detaches_it() {
unsafe {
let lc = layout_create_cell(null_mut());
let wp =
Box::leak(Box::new(std::mem::MaybeUninit::<window_pane>::uninit())).as_mut_ptr();
layout_make_leaf(lc, wp);
assert!((*lc).type_ == layout_type::LAYOUT_WINDOWPANE);
assert_eq!((*lc).wp, wp);
assert_eq!((*wp).layout_cell, lc);
layout_make_node(lc, layout_type::LAYOUT_LEFTRIGHT);
assert!((*lc).type_ == layout_type::LAYOUT_LEFTRIGHT);
assert!((*lc).wp.is_null());
assert!((*wp).layout_cell.is_null());
layout_free_cell(lc, 0);
}
}
#[test]
fn count_cells_deeper_nested_tree() {
unsafe {
let l1 = node(layout_type::LAYOUT_LEFTRIGHT, &[leaf(10, 5), leaf(10, 5)]);
let inner = node(layout_type::LAYOUT_TOPBOTTOM, &[leaf(10, 2), leaf(10, 2)]);
let l2 = node(layout_type::LAYOUT_LEFTRIGHT, &[leaf(10, 5), inner]);
let root = node(layout_type::LAYOUT_TOPBOTTOM, &[l1, l2]);
assert_eq!(layout_count_cells(root), 5);
layout_free_cell(root, 0);
}
}
#[test]
fn search_by_border_topbottom_finds_divider() {
unsafe {
let a = leaf(80, 12);
let b = leaf(80, 11);
let p = node(layout_type::LAYOUT_TOPBOTTOM, &[a, b]);
(*p).xoff = 0;
(*p).yoff = 0;
(*p).sx = 80;
(*p).sy = 24;
layout_fix_offsets1(p);
assert!(layout_search_by_border(p, 5, 3).is_null());
assert_eq!(layout_search_by_border(p, 5, 12), a);
layout_free_cell(p, 0);
}
}
#[test]
fn resize_adjust_different_direction_grows_all_children() {
unsafe {
let a = leaf(40, 10);
let b = leaf(39, 10);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
(*p).sx = 80;
(*p).sy = 10;
layout_resize_adjust(null_mut(), p, layout_type::LAYOUT_TOPBOTTOM, 5);
assert_eq!((*p).sy, 15);
assert_eq!((*a).sy, 15);
assert_eq!((*b).sy, 15);
assert_eq!((*a).sx, 40);
assert_eq!((*b).sx, 39);
layout_free_cell(p, 0);
}
}
#[test]
fn resize_adjust_same_direction_nested_round_robin() {
unsafe {
let a = leaf(10, 24);
let c = leaf(10, 24);
let d = leaf(10, 24);
let q = node(layout_type::LAYOUT_LEFTRIGHT, &[c, d]);
(*q).sx = 21; (*q).sy = 24;
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, q]);
(*p).sx = 32; (*p).sy = 24;
layout_resize_adjust(null_mut(), p, layout_type::LAYOUT_LEFTRIGHT, 2);
assert_eq!((*p).sx, 34);
assert_eq!((*a).sx, 11);
assert_eq!((*q).sx, 22);
assert_eq!((*c).sx, 11);
assert_eq!((*d).sx, 10);
layout_free_cell(p, 0);
}
}
static PBS_OE: options_table_entry = options_table_entry {
name: "pane-border-status",
type_: options_table_type::OPTIONS_TABLE_NUMBER,
default_num: 0,
..options_table_entry::const_default()
};
unsafe fn window_off() -> *mut window {
unsafe {
let w = Box::into_raw(Box::new(std::mem::zeroed::<window>()));
let opts = options_create(null_mut());
options_empty(opts, &PBS_OE);
(*w).options = opts;
w
}
}
#[test]
fn cell_is_tiled_variants() {
unsafe {
let l = leaf(80, 24);
assert_eq!(layout_cell_is_tiled(l), 1);
(*l).flags |= LAYOUT_CELL_FLOATING;
assert_eq!(layout_cell_is_tiled(l), 0);
layout_free_cell(l, 0);
let n = node(layout_type::LAYOUT_LEFTRIGHT, &[leaf(10, 5), leaf(10, 5)]);
assert_eq!(layout_cell_is_tiled(n), 0);
layout_free_cell(n, 0);
}
}
#[test]
fn resize_check_leaf_axes() {
unsafe {
let w = window_off();
let l = leaf(40, 24);
assert_eq!(layout_resize_check(w, l, layout_type::LAYOUT_LEFTRIGHT), 39);
assert_eq!(layout_resize_check(w, l, layout_type::LAYOUT_TOPBOTTOM), 23);
layout_free_cell(l, 0);
}
}
#[test]
fn resize_check_leaf_at_minimum_is_zero() {
unsafe {
let w = window_off();
let l = leaf(1, 1);
assert_eq!(layout_resize_check(w, l, layout_type::LAYOUT_LEFTRIGHT), 0);
assert_eq!(layout_resize_check(w, l, layout_type::LAYOUT_TOPBOTTOM), 0);
layout_free_cell(l, 0);
}
}
#[test]
fn resize_check_node_sum_vs_min() {
unsafe {
let w = window_off();
let a = leaf(40, 24); let b = leaf(30, 24); let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
(*p).sx = 71;
(*p).sy = 24;
assert_eq!(layout_resize_check(w, p, layout_type::LAYOUT_LEFTRIGHT), 68);
assert_eq!(layout_resize_check(w, p, layout_type::LAYOUT_TOPBOTTOM), 23);
layout_free_cell(p, 0);
}
}
#[test]
fn resize_adjust_negative_round_robin() {
unsafe {
let w = window_off();
let a = leaf(40, 24);
let b = leaf(40, 24);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
(*p).sx = 81;
(*p).sy = 24;
layout_resize_adjust(w, p, layout_type::LAYOUT_LEFTRIGHT, -3);
assert_eq!((*p).sx, 78);
assert_eq!((*a).sx, 38);
assert_eq!((*b).sx, 39);
layout_free_cell(p, 0);
}
}
#[test]
fn set_size_check_leaf_minimum() {
unsafe {
let l = leaf(80, 24);
assert!(layout_set_size_check(
null_mut(),
l,
layout_type::LAYOUT_LEFTRIGHT,
PANE_MINIMUM as i32
));
assert!(!layout_set_size_check(
null_mut(),
l,
layout_type::LAYOUT_LEFTRIGHT,
PANE_MINIMUM as i32 - 1
));
layout_free_cell(l, 0);
}
}
#[test]
fn new_pane_size_last_cell_takes_remaining() {
unsafe {
let l = leaf(40, 24);
let got = layout_new_pane_size(
null_mut(),
100,
l,
layout_type::LAYOUT_LEFTRIGHT,
50,
1, 33, );
assert_eq!(got, 33);
layout_free_cell(l, 0);
}
}
#[test]
fn search_by_border_outside_returns_null() {
unsafe {
let a = leaf(40, 24);
let b = leaf(40, 24);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b]);
(*p).xoff = 0;
(*p).yoff = 0;
layout_fix_offsets1(p);
assert!(layout_search_by_border(p, 200, 5).is_null());
layout_free_cell(p, 0);
}
}
#[test]
fn count_cells_single_leaf() {
unsafe {
let l = leaf(80, 24);
assert_eq!(layout_count_cells(l), 1);
layout_free_cell(l, 0);
}
}
#[test]
fn fix_offsets_three_leftright_children() {
unsafe {
let a = leaf(20, 24);
let b = leaf(30, 24);
let c = leaf(28, 24);
let p = node(layout_type::LAYOUT_LEFTRIGHT, &[a, b, c]);
(*p).xoff = 0;
(*p).yoff = 0;
layout_fix_offsets1(p);
assert_eq!(((*a).xoff, (*a).yoff), (0, 0));
assert_eq!(((*b).xoff, (*b).yoff), (21, 0)); assert_eq!(((*c).xoff, (*c).yoff), (52, 0)); layout_free_cell(p, 0);
}
}
#[test]
fn resize_adjust_topbottom_cross_direction() {
unsafe {
let a = leaf(80, 12);
let b = leaf(80, 11);
let p = node(layout_type::LAYOUT_TOPBOTTOM, &[a, b]);
(*p).sx = 80;
(*p).sy = 24;
layout_resize_adjust(null_mut(), p, layout_type::LAYOUT_LEFTRIGHT, 4);
assert_eq!((*p).sx, 84);
assert_eq!((*a).sx, 84);
assert_eq!((*b).sx, 84);
assert_eq!((*a).sy, 12);
assert_eq!((*b).sy, 11);
layout_free_cell(p, 0);
}
}
}