1#![expect(rustdoc::broken_intra_doc_links, reason = "github markdown callout")]
15#![cfg_attr(doc, doc = include_str!("../README.md"))]
16#![allow(
17 non_camel_case_types,
18 reason = "this lint is here instead of in Cargo.toml because of a bug in rust analyzer"
19)]
20
21use std::{
22 cmp,
23 ffi::{
24 CStr, CString, c_int, c_long, c_longlong, c_short, c_uchar, c_uint, c_ulonglong, c_void,
25 },
26 io::Write as _,
27 mem::{MaybeUninit, size_of, zeroed},
28 ptr::{NonNull, addr_of, addr_of_mut, null, null_mut},
29 sync::{
30 Mutex,
31 atomic::{self, AtomicBool, AtomicU32},
32 },
33};
34
35mod compat;
36use compat::{queue::*, strlcat, strlcpy, strtonum, strtonum_, tree::*, vis_flags};
37
38mod ncurses_;
39use ncurses_::*;
40
41pub(crate) mod libc;
42pub(crate) use libc::errno;
43pub(crate) use libc::*;
44pub(crate) use libc::{free_, memcpy_, memcpy__, streq_};
45
46#[cfg(feature = "sixel")]
47mod image_;
48#[cfg(feature = "sixel")]
49mod image_sixel;
50#[cfg(feature = "sixel")]
51use image_sixel::sixel_image;
52
53#[cfg(feature = "utempter")]
54mod utempter;
55
56mod event_;
58use event_::*;
59
60#[inline]
61const fn transmute_ptr<T>(value: Option<NonNull<T>>) -> *mut T {
62 match value {
63 Some(ptr) => ptr.as_ptr(),
64 None => null_mut(),
65 }
66}
67
68use compat::imsg::imsg; type bitstr_t = u8;
73
74unsafe fn bit_alloc(nbits: u32) -> *mut u8 {
75 unsafe { libc::calloc(nbits.div_ceil(8) as usize, 1).cast() }
76}
77unsafe fn bit_set(bits: *mut u8, i: u32) {
78 unsafe {
79 let byte_index = i / 8;
80 let bit_index = i % 8;
81 *bits.add(byte_index as usize) |= 1 << bit_index;
82 }
83}
84
85#[inline]
86unsafe fn bit_clear(bits: *mut u8, i: u32) {
87 unsafe {
88 let byte_index = i / 8;
89 let bit_index = i % 8;
90 *bits.add(byte_index as usize) &= !(1 << bit_index);
91 }
92}
93
94unsafe fn bit_nclear(bits: *mut u8, start: u32, stop: u32) {
96 unsafe {
97 for i in start..=stop {
99 bit_clear(bits, i);
100 }
101 }
102}
103
104unsafe fn bit_test(bits: *const u8, i: u32) -> bool {
105 unsafe {
106 let byte_index = i / 8;
107 let bit_index = i % 8;
108 (*bits.add(byte_index as usize) & (1 << bit_index)) != 0
109 }
110}
111
112const TTY_NAME_MAX: usize = 32;
113
114struct discr_alerts_entry;
116struct discr_all_entry;
117struct discr_by_uri_entry;
118struct discr_by_inner_entry;
119struct discr_entry;
120struct discr_name_entry;
121struct discr_pending_entry;
122struct discr_sentry;
123struct discr_time_entry;
124struct discr_tree_entry;
125struct discr_wentry;
126
127const _PATH_TTY: *const u8 = c!("/dev/tty");
129
130const _PATH_BSHELL: *const u8 = c!("/bin/sh");
131const _PATH_BSHELL_STR: &str = "/bin/sh";
132
133const _PATH_DEFPATH: *const u8 = c!("/usr/bin:/bin");
134const _PATH_DEV: *const u8 = c!("/dev/");
135const _PATH_DEVNULL: *const u8 = c!("/dev/null");
136const _PATH_VI: &str = "/usr/bin/vi";
137
138const SIZEOF_PATH_DEV: usize = 6;
139
140macro_rules! env_or {
141 ($key:literal, $default:expr) => {
142 match std::option_env!($key) {
143 Some(value) => value,
144 None => $default,
145 }
146 };
147}
148
149const TMUX_VERSION: &str = env_or!("TMUX_VERSION", env!("CARGO_PKG_VERSION"));
150const TMUX_CONF: &str = env_or!(
151 "TMUX_CONF",
152 "/etc/tmux.conf:~/.tmux.conf:$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"
153);
154const TMUX_SOCK: &str = env_or!("TMUX_SOCK", "$TMUX_TMPDIR:/tmp/");
155const TMUX_TERM: &str = env_or!("TMUX_TERM", "screen");
156const TMUX_LOCK_CMD: &str = env_or!("TMUX_LOCK_CMD", "lock -np");
157
158const PANE_MINIMUM: u32 = 1;
160
161const NAME_INTERVAL: libc::suseconds_t = 500000;
163
164const DEFAULT_XPIXEL: u32 = 16;
166const DEFAULT_YPIXEL: u32 = 32;
167
168enum_try_from!(alert_option, i32, alert_option::ALERT_OTHER);
169#[expect(dead_code, reason = "enum_try_from transmutes from i32 to enum")]
171#[repr(i32)]
172#[derive(Copy, Clone)]
173enum alert_option {
174 ALERT_NONE,
175 ALERT_ANY,
176 ALERT_CURRENT,
177 ALERT_OTHER,
178}
179
180enum_try_from!(visual_option, i32, visual_option::VISUAL_BOTH);
181#[expect(dead_code, reason = "enum_try_from transmutes from i32 to enum")]
183#[repr(i32)]
184#[derive(Copy, Clone, Eq, PartialEq)]
185enum visual_option {
186 VISUAL_OFF,
187 VISUAL_ON,
188 VISUAL_BOTH,
189}
190
191const KEYC_NONE: c_ulonglong = 0x000ff000000000;
193const KEYC_UNKNOWN: c_ulonglong = 0x000fe000000000;
194
195const KEYC_BASE: c_ulonglong = 0x0000000010e000;
198const KEYC_USER: c_ulonglong = 0x0000000010f000;
199const KEYC_USER_END: c_ulonglong = KEYC_USER + KEYC_NUSER;
200
201const KEYC_META: c_ulonglong = 0x00100000000000;
203const KEYC_CTRL: c_ulonglong = 0x00200000000000;
204const KEYC_SHIFT: c_ulonglong = 0x00400000000000;
205
206const KEYC_LITERAL: c_ulonglong = 0x01000000000000;
208const KEYC_KEYPAD: c_ulonglong = 0x02000000000000;
209const KEYC_CURSOR: c_ulonglong = 0x04000000000000;
210const KEYC_IMPLIED_META: c_ulonglong = 0x08000000000000;
211const KEYC_BUILD_MODIFIERS: c_ulonglong = 0x10000000000000;
212const KEYC_VI: c_ulonglong = 0x20000000000000;
213const KEYC_SENT: c_ulonglong = 0x40000000000000;
214
215const KEYC_MASK_MODIFIERS: c_ulonglong = 0x00f00000000000;
217const KEYC_MASK_FLAGS: c_ulonglong = 0xff000000000000;
218const KEYC_MASK_KEY: c_ulonglong = 0x000fffffffffff;
219
220const KEYC_NUSER: c_ulonglong = 1000;
221
222#[expect(non_snake_case)]
223#[inline(always)]
224fn KEYC_IS_MOUSE(key: key_code) -> bool {
225 const KEYC_MOUSE: c_ulonglong = keyc::KEYC_MOUSE as c_ulonglong;
226 const KEYC_BSPACE: c_ulonglong = keyc::KEYC_BSPACE as c_ulonglong;
227
228 (key & KEYC_MASK_KEY) >= KEYC_MOUSE && (key & KEYC_MASK_KEY) < KEYC_BSPACE
229}
230
231#[expect(non_snake_case)]
232#[inline(always)]
233fn KEYC_IS_UNICODE(key: key_code) -> bool {
234 let masked = key & KEYC_MASK_KEY;
235
236 const KEYC_BASE_END: c_ulonglong = keyc::KEYC_BASE_END as c_ulonglong;
237 masked > 0x7f
238 && !(KEYC_BASE..KEYC_BASE_END).contains(&masked)
239 && !(KEYC_USER..KEYC_USER_END).contains(&masked)
240}
241
242const KEYC_CLICK_TIMEOUT: i32 = 300;
243
244type key_code = core::ffi::c_ulonglong;
247
248#[repr(u64)]
252#[derive(Copy, Clone)]
253enum c0 {
254 C0_NUL,
255 C0_SOH,
256 C0_STX,
257 C0_ETX,
258 C0_EOT,
259 C0_ENQ,
260 C0_ASC,
261 C0_BEL,
262 C0_BS,
263 C0_HT,
264 C0_LF,
265 C0_VT,
266 C0_FF,
267 C0_CR,
268 C0_SO,
269 C0_SI,
270 C0_DLE,
271 C0_DC1,
272 C0_DC2,
273 C0_DC3,
274 C0_DC4,
275 C0_NAK,
276 C0_SYN,
277 C0_ETB,
278 C0_CAN,
279 C0_EM,
280 C0_SUB,
281 C0_ESC,
282 C0_FS,
283 C0_GS,
284 C0_RS,
285 C0_US,
286}
287
288include!("keyc_mouse_key.rs");
298
299enum_try_from!(tty_code_code, u32, tty_code_code::TTYC_XT);
300#[repr(u32)]
302#[derive(Copy, Clone)]
303enum tty_code_code {
304 TTYC_ACSC,
305 TTYC_AM,
306 TTYC_AX,
307 TTYC_BCE,
308 TTYC_BEL,
309 TTYC_BIDI,
310 TTYC_BLINK,
311 TTYC_BOLD,
312 TTYC_CIVIS,
313 TTYC_CLEAR,
314 TTYC_CLMG,
315 TTYC_CMG,
316 TTYC_CNORM,
317 TTYC_COLORS,
318 TTYC_CR,
319 TTYC_CS,
320 TTYC_CSR,
321 TTYC_CUB,
322 TTYC_CUB1,
323 TTYC_CUD,
324 TTYC_CUD1,
325 TTYC_CUF,
326 TTYC_CUF1,
327 TTYC_CUP,
328 TTYC_CUU,
329 TTYC_CUU1,
330 TTYC_CVVIS,
331 TTYC_DCH,
332 TTYC_DCH1,
333 TTYC_DIM,
334 TTYC_DL,
335 TTYC_DL1,
336 TTYC_DSBP,
337 TTYC_DSEKS,
338 TTYC_DSFCS,
339 TTYC_DSMG,
340 TTYC_E3,
341 TTYC_ECH,
342 TTYC_ED,
343 TTYC_EL,
344 TTYC_EL1,
345 TTYC_ENACS,
346 TTYC_ENBP,
347 TTYC_ENEKS,
348 TTYC_ENFCS,
349 TTYC_ENMG,
350 TTYC_FSL,
351 TTYC_HLS,
352 TTYC_HOME,
353 TTYC_HPA,
354 TTYC_ICH,
355 TTYC_ICH1,
356 TTYC_IL,
357 TTYC_IL1,
358 TTYC_INDN,
359 TTYC_INVIS,
360 TTYC_KCBT,
361 TTYC_KCUB1,
362 TTYC_KCUD1,
363 TTYC_KCUF1,
364 TTYC_KCUU1,
365 TTYC_KDC2,
366 TTYC_KDC3,
367 TTYC_KDC4,
368 TTYC_KDC5,
369 TTYC_KDC6,
370 TTYC_KDC7,
371 TTYC_KDCH1,
372 TTYC_KDN2,
373 TTYC_KDN3,
374 TTYC_KDN4,
375 TTYC_KDN5,
376 TTYC_KDN6,
377 TTYC_KDN7,
378 TTYC_KEND,
379 TTYC_KEND2,
380 TTYC_KEND3,
381 TTYC_KEND4,
382 TTYC_KEND5,
383 TTYC_KEND6,
384 TTYC_KEND7,
385 TTYC_KF1,
386 TTYC_KF10,
387 TTYC_KF11,
388 TTYC_KF12,
389 TTYC_KF13,
390 TTYC_KF14,
391 TTYC_KF15,
392 TTYC_KF16,
393 TTYC_KF17,
394 TTYC_KF18,
395 TTYC_KF19,
396 TTYC_KF2,
397 TTYC_KF20,
398 TTYC_KF21,
399 TTYC_KF22,
400 TTYC_KF23,
401 TTYC_KF24,
402 TTYC_KF25,
403 TTYC_KF26,
404 TTYC_KF27,
405 TTYC_KF28,
406 TTYC_KF29,
407 TTYC_KF3,
408 TTYC_KF30,
409 TTYC_KF31,
410 TTYC_KF32,
411 TTYC_KF33,
412 TTYC_KF34,
413 TTYC_KF35,
414 TTYC_KF36,
415 TTYC_KF37,
416 TTYC_KF38,
417 TTYC_KF39,
418 TTYC_KF4,
419 TTYC_KF40,
420 TTYC_KF41,
421 TTYC_KF42,
422 TTYC_KF43,
423 TTYC_KF44,
424 TTYC_KF45,
425 TTYC_KF46,
426 TTYC_KF47,
427 TTYC_KF48,
428 TTYC_KF49,
429 TTYC_KF5,
430 TTYC_KF50,
431 TTYC_KF51,
432 TTYC_KF52,
433 TTYC_KF53,
434 TTYC_KF54,
435 TTYC_KF55,
436 TTYC_KF56,
437 TTYC_KF57,
438 TTYC_KF58,
439 TTYC_KF59,
440 TTYC_KF6,
441 TTYC_KF60,
442 TTYC_KF61,
443 TTYC_KF62,
444 TTYC_KF63,
445 TTYC_KF7,
446 TTYC_KF8,
447 TTYC_KF9,
448 TTYC_KHOM2,
449 TTYC_KHOM3,
450 TTYC_KHOM4,
451 TTYC_KHOM5,
452 TTYC_KHOM6,
453 TTYC_KHOM7,
454 TTYC_KHOME,
455 TTYC_KIC2,
456 TTYC_KIC3,
457 TTYC_KIC4,
458 TTYC_KIC5,
459 TTYC_KIC6,
460 TTYC_KIC7,
461 TTYC_KICH1,
462 TTYC_KIND,
463 TTYC_KLFT2,
464 TTYC_KLFT3,
465 TTYC_KLFT4,
466 TTYC_KLFT5,
467 TTYC_KLFT6,
468 TTYC_KLFT7,
469 TTYC_KMOUS,
470 TTYC_KNP,
471 TTYC_KNXT2,
472 TTYC_KNXT3,
473 TTYC_KNXT4,
474 TTYC_KNXT5,
475 TTYC_KNXT6,
476 TTYC_KNXT7,
477 TTYC_KPP,
478 TTYC_KPRV2,
479 TTYC_KPRV3,
480 TTYC_KPRV4,
481 TTYC_KPRV5,
482 TTYC_KPRV6,
483 TTYC_KPRV7,
484 TTYC_KRI,
485 TTYC_KRIT2,
486 TTYC_KRIT3,
487 TTYC_KRIT4,
488 TTYC_KRIT5,
489 TTYC_KRIT6,
490 TTYC_KRIT7,
491 TTYC_KUP2,
492 TTYC_KUP3,
493 TTYC_KUP4,
494 TTYC_KUP5,
495 TTYC_KUP6,
496 TTYC_KUP7,
497 TTYC_MS,
498 TTYC_NOBR,
499 TTYC_OL,
500 TTYC_OP,
501 TTYC_RECT,
502 TTYC_REV,
503 TTYC_RGB,
504 TTYC_RI,
505 TTYC_RIN,
506 TTYC_RMACS,
507 TTYC_RMCUP,
508 TTYC_RMKX,
509 TTYC_SE,
510 TTYC_SETAB,
511 TTYC_SETAF,
512 TTYC_SETAL,
513 TTYC_SETRGBB,
514 TTYC_SETRGBF,
515 TTYC_SETULC,
516 TTYC_SETULC1,
517 TTYC_SGR0,
518 TTYC_SITM,
519 TTYC_SMACS,
520 TTYC_SMCUP,
521 TTYC_SMKX,
522 TTYC_SMOL,
523 TTYC_SMSO,
524 TTYC_SMUL,
525 TTYC_SMULX,
526 TTYC_SMXX,
527 TTYC_SXL,
528 TTYC_SS,
529 TTYC_SWD,
530 TTYC_SYNC,
531 TTYC_TC,
532 TTYC_TSL,
533 TTYC_U8,
534 TTYC_VPA,
535 TTYC_XT,
536}
537
538const WHITESPACE: *const u8 = c!(" ");
539
540enum_try_from!(modekey, i32, modekey::MODEKEY_VI);
541#[repr(i32)]
542#[derive(Copy, Clone, Eq, PartialEq)]
543enum modekey {
544 MODEKEY_EMACS = 0,
545 MODEKEY_VI = 1,
546}
547
548bitflags::bitflags! {
549 #[repr(transparent)]
551 #[derive(Copy, Clone, Eq, PartialEq)]
552 struct mode_flag : i32 {
553 const MODE_CURSOR = 0x1;
554 const MODE_INSERT = 0x2;
555 const MODE_KCURSOR = 0x4;
556 const MODE_KKEYPAD = 0x8;
557 const MODE_WRAP = 0x10;
558 const MODE_MOUSE_STANDARD = 0x20;
559 const MODE_MOUSE_BUTTON = 0x40;
560 const MODE_CURSOR_BLINKING = 0x80;
561 const MODE_MOUSE_UTF8 = 0x100;
562 const MODE_MOUSE_SGR = 0x200;
563 const MODE_BRACKETPASTE = 0x400;
564 const MODE_FOCUSON = 0x800;
565 const MODE_MOUSE_ALL = 0x1000;
566 const MODE_ORIGIN = 0x2000;
567 const MODE_CRLF = 0x4000;
568 const MODE_KEYS_EXTENDED = 0x8000;
569 const MODE_CURSOR_VERY_VISIBLE = 0x10000;
570 const MODE_CURSOR_BLINKING_SET = 0x20000;
571 const MODE_KEYS_EXTENDED_2 = 0x40000;
572 }
573}
574
575#[expect(dead_code)]
576const ALL_MODES: i32 = 0xffffff;
577const ALL_MOUSE_MODES: mode_flag = mode_flag::MODE_MOUSE_STANDARD
578 .union(mode_flag::MODE_MOUSE_BUTTON)
579 .union(mode_flag::MODE_MOUSE_ALL);
580const MOTION_MOUSE_MODES: mode_flag = mode_flag::MODE_MOUSE_BUTTON.union(mode_flag::MODE_MOUSE_ALL);
581const CURSOR_MODES: mode_flag = mode_flag::MODE_CURSOR
582 .union(mode_flag::MODE_CURSOR_BLINKING)
583 .union(mode_flag::MODE_CURSOR_VERY_VISIBLE);
584const EXTENDED_KEY_MODES: mode_flag =
585 mode_flag::MODE_KEYS_EXTENDED.union(mode_flag::MODE_KEYS_EXTENDED_2);
586
587const MOUSE_PARAM_MAX: u32 = 0xff;
589const MOUSE_PARAM_UTF8_MAX: u32 = 0x7ff;
590const MOUSE_PARAM_BTN_OFF: u32 = 0x20;
591const MOUSE_PARAM_POS_OFF: u32 = 0x21;
592
593type utf8_char = c_uint;
595
596const UTF8_SIZE: usize = 21;
600
601#[repr(C)]
602#[derive(Copy, Clone)]
603struct utf8_data {
604 data: [u8; UTF8_SIZE],
605
606 have: u8,
607 size: u8, width: u8,
610}
611
612impl utf8_data {
613 const fn new<const N: usize>(data: [u8; N], have: u8, size: u8, width: u8) -> Self {
614 if N >= UTF8_SIZE {
615 panic!("invalid size");
616 }
617
618 let mut padded_data = [0u8; UTF8_SIZE];
619 let mut i = 0usize;
620 while i < N {
621 padded_data[i] = data[i];
622 i += 1;
623 }
624
625 Self {
626 data: padded_data,
627 have,
628 size,
629 width,
630 }
631 }
632
633 fn initialized_slice(&self) -> &[u8] {
634 &self.data[..self.size as usize]
635 }
636}
637
638#[repr(i32)]
639#[derive(Copy, Clone, Eq, PartialEq)]
640enum utf8_state {
641 UTF8_MORE,
642 UTF8_DONE,
643 UTF8_ERROR,
644}
645
646const COLOUR_FLAG_256: i32 = 0x01000000;
648const COLOUR_FLAG_RGB: i32 = 0x02000000;
649
650#[expect(non_snake_case)]
652#[inline]
653fn COLOUR_DEFAULT(c: i32) -> bool {
654 c == 8 || c == 9
655}
656
657#[repr(C)]
659#[derive(Copy, Clone)]
660struct colour_palette {
661 fg: i32,
662 bg: i32,
663
664 palette: *mut i32,
665 default_palette: *mut i32,
666}
667
668bitflags::bitflags! {
670 #[repr(transparent)]
672 #[derive(Copy, Clone, Eq, PartialEq)]
673 struct grid_attr : u16 {
674 const GRID_ATTR_BRIGHT = 0x1;
675 const GRID_ATTR_DIM = 0x2;
676 const GRID_ATTR_UNDERSCORE = 0x4;
677 const GRID_ATTR_BLINK = 0x8;
678 const GRID_ATTR_REVERSE = 0x10;
679 const GRID_ATTR_HIDDEN = 0x20;
680 const GRID_ATTR_ITALICS = 0x40;
681 const GRID_ATTR_CHARSET = 0x80; const GRID_ATTR_STRIKETHROUGH = 0x100;
683 const GRID_ATTR_UNDERSCORE_2 = 0x200;
684 const GRID_ATTR_UNDERSCORE_3 = 0x400;
685 const GRID_ATTR_UNDERSCORE_4 = 0x800;
686 const GRID_ATTR_UNDERSCORE_5 = 0x1000;
687 const GRID_ATTR_OVERLINE = 0x2000;
688 }
689}
690
691const GRID_ATTR_ALL_UNDERSCORE: grid_attr = grid_attr::GRID_ATTR_UNDERSCORE
693 .union(grid_attr::GRID_ATTR_UNDERSCORE_2)
694 .union(grid_attr::GRID_ATTR_UNDERSCORE_3)
695 .union(grid_attr::GRID_ATTR_UNDERSCORE_4)
696 .union(grid_attr::GRID_ATTR_UNDERSCORE_5);
697
698bitflags::bitflags! {
699 #[repr(transparent)]
701 #[derive(Copy, Clone, Eq, PartialEq)]
702 struct grid_flag : u8 {
703 const FG256 = 0x1;
704 const BG256 = 0x2;
705 const PADDING = 0x4;
706 const EXTENDED = 0x8;
707 const SELECTED = 0x10;
708 const NOPALETTE = 0x20;
709 const CLEARED = 0x40;
710 }
711}
712
713bitflags::bitflags! {
714 #[repr(transparent)]
716 #[derive(Copy, Clone, Eq, PartialEq)]
717 struct grid_line_flag: i32 {
718 const WRAPPED = 1 << 0; const EXTENDED = 1 << 1; const DEAD = 1 << 2; const START_PROMPT = 1 << 3; const START_OUTPUT = 1 << 4; }
724}
725
726bitflags::bitflags! {
727 #[repr(transparent)]
729 #[derive(Copy, Clone, Eq, PartialEq)]
730 struct grid_string_flags: i32 {
731 const GRID_STRING_WITH_SEQUENCES = 0x1;
732 const GRID_STRING_ESCAPE_SEQUENCES = 0x2;
733 const GRID_STRING_TRIM_SPACES = 0x4;
734 const GRID_STRING_USED_ONLY = 0x8;
735 const GRID_STRING_EMPTY_CELLS = 0x10;
736 }
737}
738
739#[repr(i32)]
741#[derive(Copy, Clone, Eq, PartialEq)]
742enum cell_type {
743 CELL_INSIDE = 0,
744 CELL_TOPBOTTOM = 1,
745 CELL_LEFTRIGHT = 2,
746 CELL_TOPLEFT = 3,
747 CELL_TOPRIGHT = 4,
748 CELL_BOTTOMLEFT = 5,
749 CELL_BOTTOMRIGHT = 6,
750 CELL_TOPJOIN = 7,
751 CELL_BOTTOMJOIN = 8,
752 CELL_LEFTJOIN = 9,
753 CELL_RIGHTJOIN = 10,
754 CELL_JOIN = 11,
755 CELL_OUTSIDE = 12,
756}
757use cell_type::*; const CELL_BORDERS: [u8; 13] = [
761 b' ', b'x', b'q', b'l', b'k', b'm', b'j', b'w', b'v', b't', b'u', b'n', b'~',
762];
763const SIMPLE_BORDERS: [u8; 13] = [
764 b' ', b'|', b'-', b'+', b'+', b'+', b'+', b'+', b'+', b'+', b'+', b'+', b'.',
765];
766const PADDED_BORDERS: [u8; 13] = [b' '; 13];
767
768#[repr(C)]
770#[derive(Copy, Clone)]
771struct grid_cell {
772 data: utf8_data,
773 attr: grid_attr,
774 flags: grid_flag,
775 fg: i32,
776 bg: i32,
777 us: i32,
778 link: u32,
779}
780
781impl grid_cell {
782 const fn new(
783 data: utf8_data,
784 attr: grid_attr,
785 flags: grid_flag,
786 fg: i32,
787 bg: i32,
788 us: i32,
789 link: u32,
790 ) -> Self {
791 Self {
792 data,
793 attr,
794 flags,
795 fg,
796 bg,
797 us,
798 link,
799 }
800 }
801}
802
803#[repr(C)]
805struct grid_extd_entry {
806 data: utf8_char,
807 attr: u16,
808 flags: u8,
809 fg: i32,
810 bg: i32,
811 us: i32,
812 link: u32,
813}
814
815#[derive(Copy, Clone)]
816#[repr(C, align(4))]
817struct grid_cell_entry_data {
818 attr: u8,
819 fg: u8,
820 bg: u8,
821 data: u8,
822}
823
824#[repr(C)]
825union grid_cell_entry_union {
826 offset: u32,
827 data: grid_cell_entry_data,
828}
829
830#[repr(C)]
831struct grid_cell_entry {
832 union_: grid_cell_entry_union,
833 flags: grid_flag,
834}
835
836#[repr(C)]
838struct grid_line {
839 celldata: *mut grid_cell_entry,
840 cellused: u32,
841 cellsize: u32,
842
843 extddata: *mut grid_extd_entry,
844 extdsize: u32,
845
846 flags: grid_line_flag,
847 time: time_t,
848}
849
850const GRID_HISTORY: i32 = 0x1; #[repr(C)]
854struct grid {
855 flags: i32,
856
857 sx: u32,
858 sy: u32,
859
860 hscrolled: u32,
861 hsize: u32,
862 hlimit: u32,
863
864 linedata: *mut grid_line,
865}
866
867#[repr(C)]
869struct grid_reader {
870 gd: *mut grid,
871 cx: u32,
872 cy: u32,
873}
874
875#[repr(i32)]
877#[derive(Copy, Clone, Eq, PartialEq)]
878enum style_align {
879 STYLE_ALIGN_DEFAULT,
880 STYLE_ALIGN_LEFT,
881 STYLE_ALIGN_CENTRE,
882 STYLE_ALIGN_RIGHT,
883 STYLE_ALIGN_ABSOLUTE_CENTRE,
884}
885
886#[repr(i32)]
888#[derive(Copy, Clone, Eq, PartialEq)]
889enum style_list {
890 STYLE_LIST_OFF,
891 STYLE_LIST_ON,
892 STYLE_LIST_FOCUS,
893 STYLE_LIST_LEFT_MARKER,
894 STYLE_LIST_RIGHT_MARKER,
895}
896
897#[repr(i32)]
899#[derive(Copy, Clone, Eq, PartialEq)]
900enum style_range_type {
901 STYLE_RANGE_NONE,
902 STYLE_RANGE_LEFT,
903 STYLE_RANGE_RIGHT,
904 STYLE_RANGE_PANE,
905 STYLE_RANGE_WINDOW,
906 STYLE_RANGE_SESSION,
907 STYLE_RANGE_USER,
908}
909
910impl_tailq_entry!(style_range, entry, tailq_entry<style_range>);
911#[repr(C)]
913struct style_range {
914 type_: style_range_type,
915 argument: u32,
916 string: [u8; 16],
917 start: u32,
918 end: u32,
920
921 entry: tailq_entry<style_range>,
923}
924type style_ranges = tailq_head<style_range>;
925
926#[repr(i32)]
928#[derive(Copy, Clone, Eq, PartialEq)]
929enum style_default_type {
930 STYLE_DEFAULT_BASE,
931 STYLE_DEFAULT_PUSH,
932 STYLE_DEFAULT_POP,
933}
934
935#[repr(C)]
937#[derive(Copy, Clone)]
938struct style {
939 gc: grid_cell,
940 ignore: i32,
941
942 fill: i32,
943 align: style_align,
944 list: style_list,
945
946 range_type: style_range_type,
947 range_argument: u32,
948 range_string: [u8; 16],
949
950 default_type: style_default_type,
951}
952
953#[cfg(feature = "sixel")]
954impl crate::compat::queue::Entry<image, discr_all_entry> for image {
955 unsafe fn entry(this: *mut Self) -> *mut tailq_entry<image> {
956 unsafe { &raw mut (*this).all_entry }
957 }
958}
959#[cfg(feature = "sixel")]
960impl crate::compat::queue::Entry<image, discr_entry> for image {
961 unsafe fn entry(this: *mut Self) -> *mut tailq_entry<image> {
962 unsafe { &raw mut (*this).entry }
963 }
964}
965#[cfg(feature = "sixel")]
966#[repr(C)]
967#[derive(Copy, Clone)]
968struct image {
969 s: *mut screen,
970 data: *mut sixel_image,
971 fallback: *mut u8,
972 px: u32,
973 py: u32,
974 sx: u32,
975 sy: u32,
976
977 all_entry: tailq_entry<image>,
978 entry: tailq_entry<image>,
979}
980
981#[cfg(feature = "sixel")]
982type images = tailq_head<image>;
983
984#[repr(i32)]
986#[derive(Copy, Clone, Eq, PartialEq)]
987enum screen_cursor_style {
988 SCREEN_CURSOR_DEFAULT,
989 SCREEN_CURSOR_BLOCK,
990 SCREEN_CURSOR_UNDERLINE,
991 SCREEN_CURSOR_BAR,
992}
993
994#[repr(C)]
996#[derive(Clone)]
997struct screen {
998 title: *mut u8,
999 path: *mut u8,
1000 titles: *mut screen_titles,
1001
1002 grid: *mut grid,
1004
1005 cx: u32,
1007 cy: u32,
1009
1010 cstyle: screen_cursor_style,
1012 default_cstyle: screen_cursor_style,
1013 ccolour: i32,
1015 default_ccolour: i32,
1017
1018 rupper: u32,
1020 rlower: u32,
1022
1023 mode: mode_flag,
1024 default_mode: mode_flag,
1025
1026 saved_cx: u32,
1027 saved_cy: u32,
1028 saved_grid: *mut grid,
1029 saved_cell: grid_cell,
1030 saved_flags: i32,
1031
1032 tabs: *mut bitstr_t,
1033 sel: *mut screen_sel,
1034
1035 #[cfg(feature = "sixel")]
1036 images: images,
1037
1038 write_list: *mut screen_write_cline,
1039
1040 hyperlinks: *mut hyperlinks,
1041}
1042
1043const SCREEN_WRITE_SYNC: i32 = 0x1;
1044
1045type screen_write_init_ctx_cb = Option<unsafe fn(*mut screen_write_ctx, *mut tty_ctx)>;
1047#[repr(C)]
1048struct screen_write_ctx {
1049 wp: *mut window_pane,
1050 s: *mut screen,
1051
1052 flags: i32,
1053
1054 init_ctx_cb: screen_write_init_ctx_cb,
1055
1056 arg: *mut c_void,
1057
1058 item: *mut screen_write_citem,
1059 scrolled: u32,
1060 bg: u32,
1061}
1062
1063enum_try_from!(box_lines, i32, box_lines::BOX_LINES_NONE);
1064#[expect(dead_code, reason = "enum_try_from transmutes from i32 to enum")]
1066#[repr(i32)]
1067#[derive(Copy, Clone, Default, Eq, PartialEq)]
1068enum box_lines {
1069 #[default]
1070 BOX_LINES_DEFAULT = -1,
1071 BOX_LINES_SINGLE,
1072 BOX_LINES_DOUBLE,
1073 BOX_LINES_HEAVY,
1074 BOX_LINES_SIMPLE,
1075 BOX_LINES_ROUNDED,
1076 BOX_LINES_PADDED,
1077 BOX_LINES_NONE,
1078}
1079
1080enum_try_from!(pane_lines, i32, pane_lines::PANE_LINES_NUMBER);
1081#[expect(dead_code, reason = "enum_try_from transmutes from i32 to enum")]
1082#[repr(i32)]
1084#[derive(Copy, Clone, Default, Eq, PartialEq)]
1085enum pane_lines {
1086 #[default]
1087 PANE_LINES_SINGLE,
1088 PANE_LINES_DOUBLE,
1089 PANE_LINES_HEAVY,
1090 PANE_LINES_SIMPLE,
1091 PANE_LINES_NUMBER,
1092}
1093
1094enum_try_from!(
1095 pane_border_indicator,
1096 i32,
1097 pane_border_indicator::PANE_BORDER_BOTH
1098);
1099#[expect(dead_code, reason = "enum_try_from transmutes from i32 to enum")]
1100#[repr(i32)]
1101#[derive(Copy, Clone)]
1102enum pane_border_indicator {
1103 PANE_BORDER_OFF,
1104 PANE_BORDER_COLOUR,
1105 PANE_BORDER_ARROWS,
1106 PANE_BORDER_BOTH,
1107}
1108
1109const WINDOW_PANE_NO_MODE: i32 = 0;
1111const WINDOW_PANE_COPY_MODE: i32 = 1;
1112const WINDOW_PANE_VIEW_MODE: i32 = 2;
1113
1114#[repr(C)]
1116struct screen_redraw_ctx {
1117 c: *mut client,
1118
1119 statuslines: u32,
1120 statustop: i32,
1121
1122 pane_status: pane_status,
1123 pane_lines: pane_lines,
1124
1125 no_pane_gc: grid_cell,
1126 no_pane_gc_set: i32,
1127
1128 sx: u32,
1129 sy: u32,
1130 ox: u32,
1131 oy: u32,
1132}
1133
1134unsafe fn screen_size_x(s: *const screen) -> u32 {
1135 unsafe { (*(*s).grid).sx }
1136}
1137unsafe fn screen_size_y(s: *const screen) -> u32 {
1138 unsafe { (*(*s).grid).sy }
1139}
1140unsafe fn screen_hsize(s: *const screen) -> u32 {
1141 unsafe { (*(*s).grid).hsize }
1142}
1143unsafe fn screen_hlimit(s: *const screen) -> u32 {
1144 unsafe { (*(*s).grid).hlimit }
1145}
1146
1147#[repr(C)]
1149struct menu_item {
1150 name: SyncCharPtr,
1151 key: key_code,
1152 command: SyncCharPtr,
1153}
1154impl menu_item {
1155 const fn new(name: &'static CStr, key: key_code, command: *const u8) -> Self {
1156 Self {
1157 name: SyncCharPtr::new(name),
1158 key,
1159 command: SyncCharPtr(command),
1160 }
1161 }
1162}
1163
1164#[repr(C)]
1165struct menu {
1166 title: *const u8,
1167 items: *mut menu_item,
1168 count: u32,
1169 width: u32,
1170}
1171type menu_choice_cb = Option<unsafe fn(*mut menu, u32, key_code, *mut c_void)>;
1172
1173#[expect(clippy::type_complexity)]
1174#[repr(C)]
1177struct window_mode {
1178 name: SyncCharPtr,
1179 default_format: SyncCharPtr,
1180
1181 init: unsafe fn(NonNull<window_mode_entry>, *mut cmd_find_state, *mut args) -> *mut screen,
1182 free: unsafe fn(NonNull<window_mode_entry>),
1183 resize: unsafe fn(NonNull<window_mode_entry>, u32, u32),
1184 update: Option<unsafe fn(NonNull<window_mode_entry>)>,
1185 key: Option<
1186 unsafe fn(
1187 NonNull<window_mode_entry>,
1188 *mut client,
1189 *mut session,
1190 *mut winlink,
1191 key_code,
1192 *mut mouse_event,
1193 ),
1194 >,
1195
1196 key_table: Option<unsafe fn(*mut window_mode_entry) -> *const u8>,
1197 command: Option<
1198 unsafe fn(
1199 NonNull<window_mode_entry>,
1200 *mut client,
1201 *mut session,
1202 *mut winlink,
1203 *mut args,
1204 *mut mouse_event,
1205 ),
1206 >,
1207 formats: Option<unsafe fn(*mut window_mode_entry, *mut format_tree)>,
1208}
1209
1210impl_tailq_entry!(window_mode_entry, entry, tailq_entry<window_mode_entry>);
1212#[repr(C)]
1213struct window_mode_entry {
1214 wp: *mut window_pane,
1215 swp: *mut window_pane,
1216
1217 mode: *const window_mode,
1218 data: *mut c_void,
1219
1220 screen: *mut screen,
1221 prefix: u32,
1222
1223 entry: tailq_entry<window_mode_entry>,
1225}
1226
1227#[repr(C)]
1229#[derive(Copy, Clone)]
1230struct window_pane_offset {
1231 used: usize,
1232}
1233
1234impl_tailq_entry!(window_pane_resize, entry, tailq_entry<window_pane_resize>);
1235#[repr(C)]
1237struct window_pane_resize {
1238 sx: u32,
1239 sy: u32,
1240
1241 osx: u32,
1242 osy: u32,
1243
1244 entry: tailq_entry<window_pane_resize>,
1245}
1246type window_pane_resizes = tailq_head<window_pane_resize>;
1247
1248bitflags::bitflags! {
1249 #[repr(transparent)]
1250 #[derive(Copy, Clone, Eq, PartialEq)]
1251 struct window_pane_flags : i32 {
1252 const PANE_REDRAW = 0x1;
1253 const PANE_DROP = 0x2;
1254 const PANE_FOCUSED = 0x4;
1255 const PANE_VISITED = 0x8;
1256 const PANE_INPUTOFF = 0x40;
1259 const PANE_CHANGED = 0x80;
1260 const PANE_EXITED = 0x100;
1261 const PANE_STATUSREADY = 0x200;
1262 const PANE_STATUSDRAWN = 0x400;
1263 const PANE_EMPTY = 0x800;
1264 const PANE_STYLECHANGED = 0x1000;
1265 const PANE_UNSEENCHANGES = 0x2000;
1266 }
1267}
1268
1269#[repr(C)]
1271struct window_pane {
1272 id: u32,
1273 active_point: u32,
1274
1275 window: *mut window,
1276 options: *mut options,
1277
1278 layout_cell: *mut layout_cell,
1279 saved_layout_cell: *mut layout_cell,
1280
1281 sx: u32,
1282 sy: u32,
1283
1284 xoff: u32,
1285 yoff: u32,
1286
1287 flags: window_pane_flags,
1288
1289 argc: i32,
1290 argv: *mut *mut u8,
1291 shell: *mut u8,
1292 cwd: *mut u8,
1293
1294 pid: pid_t,
1295 tty: [u8; TTY_NAME_MAX],
1296 status: i32,
1297 dead_time: timeval,
1298
1299 fd: i32,
1300 event: *mut bufferevent,
1301
1302 offset: window_pane_offset,
1303 base_offset: usize,
1304
1305 resize_queue: window_pane_resizes,
1306 resize_timer: event,
1307
1308 ictx: *mut input_ctx,
1309
1310 cached_gc: grid_cell,
1311 cached_active_gc: grid_cell,
1312 palette: colour_palette,
1313
1314 pipe_fd: i32,
1315 pipe_event: *mut bufferevent,
1316 pipe_offset: window_pane_offset,
1317
1318 screen: *mut screen,
1319 base: screen,
1320
1321 status_screen: screen,
1322 status_size: usize,
1323
1324 modes: tailq_head<window_mode_entry>,
1325
1326 searchstr: *mut u8,
1327 searchregex: i32,
1328
1329 border_gc_set: i32,
1330 border_gc: grid_cell,
1331
1332 control_bg: i32,
1333 control_fg: i32,
1334
1335 entry: tailq_entry<window_pane>,
1337 sentry: tailq_entry<window_pane>,
1339 tree_entry: rb_entry<window_pane>,
1340}
1341type window_panes = tailq_head<window_pane>;
1342type window_pane_tree = rb_head<window_pane>;
1343
1344impl Entry<window_pane, discr_entry> for window_pane {
1345 unsafe fn entry(this: *mut Self) -> *mut tailq_entry<window_pane> {
1346 unsafe { &raw mut (*this).entry }
1347 }
1348}
1349impl Entry<window_pane, discr_sentry> for window_pane {
1350 unsafe fn entry(this: *mut Self) -> *mut tailq_entry<window_pane> {
1351 unsafe { &raw mut (*this).sentry }
1352 }
1353}
1354
1355bitflags::bitflags! {
1356 #[repr(transparent)]
1357 #[derive(Copy, Clone, Eq, PartialEq)]
1358 struct window_flag: i32 {
1359 const BELL = 0x1;
1360 const ACTIVITY = 0x2;
1361 const SILENCE = 0x4;
1362 const ZOOMED = 0x8;
1363 const WASZOOMED = 0x10;
1364 const RESIZE = 0x20;
1365 }
1366}
1367const WINDOW_ALERTFLAGS: window_flag = window_flag::BELL
1368 .union(window_flag::ACTIVITY)
1369 .union(window_flag::SILENCE);
1370
1371#[repr(C)]
1373struct window {
1374 id: u32,
1375 latest: *mut c_void,
1376
1377 name: *mut u8,
1378 name_event: event,
1379 name_time: timeval,
1380
1381 alerts_timer: event,
1382 offset_timer: event,
1383
1384 activity_time: timeval,
1385
1386 active: *mut window_pane,
1387 last_panes: window_panes,
1388 panes: window_panes,
1389
1390 lastlayout: i32,
1391 layout_root: *mut layout_cell,
1392 saved_layout_root: *mut layout_cell,
1393 old_layout: *mut u8,
1394
1395 sx: u32,
1396 sy: u32,
1397 manual_sx: u32,
1398 manual_sy: u32,
1399 xpixel: u32,
1400 ypixel: u32,
1401
1402 new_sx: u32,
1403 new_sy: u32,
1404 new_xpixel: u32,
1405 new_ypixel: u32,
1406
1407 fill_character: *mut utf8_data,
1408 flags: window_flag,
1409
1410 alerts_queued: i32,
1411 alerts_entry: tailq_entry<window>,
1412
1413 options: *mut options,
1414
1415 references: u32,
1416 winlinks: tailq_head<winlink>,
1417 entry: rb_entry<window>,
1418}
1419type windows = rb_head<window>;
1420impl crate::compat::queue::Entry<window, discr_alerts_entry> for window {
1423 unsafe fn entry(this: *mut Self) -> *mut tailq_entry<window> {
1424 unsafe { &raw mut (*this).alerts_entry }
1425 }
1426}
1427
1428bitflags::bitflags! {
1429 #[repr(transparent)]
1430 #[derive(Copy, Clone, Eq, PartialEq)]
1431 struct winlink_flags: i32 {
1432 const WINLINK_BELL = 0x1;
1433 const WINLINK_ACTIVITY = 0x2;
1434 const WINLINK_SILENCE = 0x4;
1435 const WINLINK_VISITED = 0x8;
1436 }
1437}
1438const WINLINK_ALERTFLAGS: winlink_flags = winlink_flags::WINLINK_BELL
1439 .union(winlink_flags::WINLINK_ACTIVITY)
1440 .union(winlink_flags::WINLINK_SILENCE);
1441
1442#[repr(C)]
1443#[derive(Copy, Clone)]
1444struct winlink {
1445 idx: i32,
1446 session: *mut session,
1447 window: *mut window,
1448
1449 flags: winlink_flags,
1450
1451 entry: rb_entry<winlink>,
1452
1453 wentry: tailq_entry<winlink>,
1454 sentry: tailq_entry<winlink>,
1455}
1456
1457impl crate::compat::queue::Entry<winlink, discr_wentry> for winlink {
1458 unsafe fn entry(this: *mut Self) -> *mut tailq_entry<winlink> {
1459 unsafe { &raw mut (*this).wentry }
1460 }
1461}
1462
1463impl crate::compat::queue::Entry<winlink, discr_sentry> for winlink {
1464 unsafe fn entry(this: *mut Self) -> *mut tailq_entry<winlink> {
1465 unsafe { &raw mut (*this).sentry }
1466 }
1467}
1468
1469type winlinks = rb_head<winlink>;
1470type winlink_stack = tailq_head<winlink>;
1472enum_try_from!(
1475 window_size_option,
1476 i32,
1477 window_size_option::WINDOW_SIZE_LATEST
1478);
1479#[repr(i32)]
1481#[derive(Copy, Clone, Eq, PartialEq)]
1482enum window_size_option {
1483 WINDOW_SIZE_LARGEST,
1484 WINDOW_SIZE_SMALLEST,
1485 WINDOW_SIZE_MANUAL,
1486 WINDOW_SIZE_LATEST,
1487}
1488
1489enum_try_from!(pane_status, i32, pane_status::PANE_STATUS_BOTTOM);
1490#[repr(i32)]
1492#[derive(Copy, Clone, Eq, PartialEq)]
1493enum pane_status {
1494 PANE_STATUS_OFF,
1495 PANE_STATUS_TOP,
1496 PANE_STATUS_BOTTOM,
1497}
1498
1499enum_try_from!(layout_type, i32, layout_type::LAYOUT_WINDOWPANE);
1500#[repr(i32)]
1502#[derive(Copy, Clone, Eq, PartialEq)]
1503enum layout_type {
1504 LAYOUT_LEFTRIGHT,
1505 LAYOUT_TOPBOTTOM,
1506 LAYOUT_WINDOWPANE,
1507}
1508
1509type layout_cells = tailq_head<layout_cell>;
1511
1512impl_tailq_entry!(layout_cell, entry, tailq_entry<layout_cell>);
1513#[repr(C)]
1515struct layout_cell {
1516 type_: layout_type,
1517
1518 parent: *mut layout_cell,
1519
1520 sx: u32,
1521 sy: u32,
1522
1523 xoff: u32,
1524 yoff: u32,
1525
1526 wp: *mut window_pane,
1527 cells: layout_cells,
1528
1529 entry: tailq_entry<layout_cell>,
1530}
1531
1532bitflags::bitflags! {
1533 #[repr(transparent)]
1534 #[derive(Copy, Clone)]
1535 struct environ_flags: i32 {
1536 const ENVIRON_HIDDEN = 0x1;
1537 }
1538}
1539const ENVIRON_HIDDEN: environ_flags = environ_flags::ENVIRON_HIDDEN;
1540
1541#[repr(C)]
1543struct environ_entry {
1544 name: Option<NonNull<u8>>,
1545 value: Option<NonNull<u8>>,
1546
1547 flags: environ_flags,
1548 entry: rb_entry<environ_entry>,
1549}
1550
1551#[repr(C)]
1553struct session_group {
1554 name: *const u8,
1555 sessions: tailq_head<session>,
1556
1557 entry: rb_entry<session_group>,
1558}
1559type session_groups = rb_head<session_group>;
1560
1561const SESSION_PASTING: i32 = 0x1;
1562const SESSION_ALERTED: i32 = 0x2;
1563
1564#[repr(C)]
1565struct session {
1566 id: u32,
1567 name: *mut u8,
1568 cwd: *mut u8,
1569
1570 creation_time: timeval,
1571 last_attached_time: timeval,
1572 activity_time: timeval,
1573 last_activity_time: timeval,
1574
1575 lock_timer: event,
1576
1577 curw: *mut winlink,
1578 lastw: winlink_stack,
1579 windows: winlinks,
1580
1581 statusat: i32,
1582 statuslines: u32,
1583
1584 options: *mut options,
1585
1586 flags: i32,
1587
1588 attached: u32,
1589
1590 tio: *mut termios,
1591
1592 environ: *mut environ,
1593
1594 references: i32,
1595
1596 gentry: tailq_entry<session>,
1597 entry: rb_entry<session>,
1598}
1599type sessions = rb_head<session>;
1600impl_tailq_entry!(session, gentry, tailq_entry<session>);
1601
1602const MOUSE_MASK_BUTTONS: u32 = 195;
1603const MOUSE_MASK_SHIFT: u32 = 4;
1604const MOUSE_MASK_META: u32 = 8;
1605const MOUSE_MASK_CTRL: u32 = 16;
1606const MOUSE_MASK_DRAG: u32 = 32;
1607const MOUSE_MASK_MODIFIERS: u32 = MOUSE_MASK_SHIFT | MOUSE_MASK_META | MOUSE_MASK_CTRL;
1608
1609const MOUSE_WHEEL_UP: u32 = 64;
1611const MOUSE_WHEEL_DOWN: u32 = 65;
1612
1613const MOUSE_BUTTON_1: u32 = 0;
1615const MOUSE_BUTTON_2: u32 = 1;
1616const MOUSE_BUTTON_3: u32 = 2;
1617const MOUSE_BUTTON_6: u32 = 66;
1618const MOUSE_BUTTON_7: u32 = 67;
1619const MOUSE_BUTTON_8: u32 = 128;
1620const MOUSE_BUTTON_9: u32 = 129;
1621const MOUSE_BUTTON_10: u32 = 130;
1622const MOUSE_BUTTON_11: u32 = 131;
1623
1624#[expect(non_snake_case)]
1626#[inline]
1627fn MOUSE_BUTTONS(b: u32) -> u32 {
1628 b & MOUSE_MASK_BUTTONS
1629}
1630#[expect(non_snake_case)]
1631#[inline]
1632fn MOUSE_WHEEL(b: u32) -> bool {
1633 ((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_UP || ((b) & MOUSE_MASK_BUTTONS) == MOUSE_WHEEL_DOWN
1634}
1635#[expect(non_snake_case)]
1636#[inline]
1637fn MOUSE_DRAG(b: u32) -> bool {
1638 b & MOUSE_MASK_DRAG != 0
1639}
1640#[expect(non_snake_case)]
1641#[inline]
1642fn MOUSE_RELEASE(b: u32) -> bool {
1643 b & MOUSE_MASK_BUTTONS == 3
1644}
1645
1646#[repr(C)]
1648#[derive(Copy, Clone)]
1649struct mouse_event {
1650 valid: bool,
1651 ignore: i32,
1652
1653 key: key_code,
1654
1655 statusat: i32,
1656 statuslines: u32,
1657
1658 x: u32,
1659 y: u32,
1660 b: u32,
1661
1662 lx: u32,
1663 ly: u32,
1664 lb: u32,
1665
1666 ox: u32,
1667 oy: u32,
1668
1669 s: i32,
1670 w: i32,
1671 wp: i32,
1672
1673 sgr_type: u32,
1674 sgr_b: u32,
1675}
1676
1677#[repr(C)]
1679struct key_event {
1680 key: key_code,
1681 m: mouse_event,
1682}
1683
1684bitflags::bitflags! {
1685 #[repr(transparent)]
1686 #[derive(Copy, Clone)]
1687 struct term_flags: i32 {
1688 const TERM_256COLOURS = 0x1;
1689 const TERM_NOAM = 0x2;
1690 const TERM_DECSLRM = 0x4;
1691 const TERM_DECFRA = 0x8;
1692 const TERM_RGBCOLOURS = 0x10;
1693 const TERM_VT100LIKE = 0x20;
1694 const TERM_SIXEL = 0x40;
1695 }
1696}
1697
1698#[repr(C)]
1700struct tty_term {
1701 name: *mut u8,
1702 tty: *mut tty,
1703 features: i32,
1704
1705 acs: [[u8; 2]; c_uchar::MAX as usize + 1],
1706
1707 codes: *mut tty_code,
1708
1709 flags: term_flags,
1710
1711 entry: list_entry<tty_term>,
1712}
1713type tty_terms = list_head<tty_term>;
1714impl ListEntry<tty_term, discr_entry> for tty_term {
1715 unsafe fn field(this: *mut Self) -> *mut list_entry<tty_term> {
1716 unsafe { &raw mut (*this).entry }
1717 }
1718}
1719
1720bitflags::bitflags! {
1721 #[repr(transparent)]
1722 #[derive(Copy, Clone)]
1723 struct tty_flags: i32 {
1724 const TTY_NOCURSOR = 0x1;
1725 const TTY_FREEZE = 0x2;
1726 const TTY_TIMER = 0x4;
1727 const TTY_NOBLOCK = 0x8;
1728 const TTY_STARTED = 0x10;
1729 const TTY_OPENED = 0x20;
1730 const TTY_OSC52QUERY = 0x40;
1731 const TTY_BLOCK = 0x80;
1732 const TTY_HAVEDA = 0x100; const TTY_HAVEXDA = 0x200;
1734 const TTY_SYNCING = 0x400;
1735 const TTY_HAVEDA2 = 0x800; }
1737}
1738const TTY_ALL_REQUEST_FLAGS: tty_flags = tty_flags::TTY_HAVEDA
1739 .union(tty_flags::TTY_HAVEDA2)
1740 .union(tty_flags::TTY_HAVEXDA);
1741
1742#[repr(C)]
1744struct tty {
1745 client: *mut client,
1746 start_timer: event,
1747 clipboard_timer: event,
1748 last_requests: time_t,
1749
1750 sx: u32,
1751 sy: u32,
1752
1753 xpixel: u32,
1754 ypixel: u32,
1755
1756 cx: u32,
1757 cy: u32,
1758 cstyle: screen_cursor_style,
1759 ccolour: i32,
1760
1761 oflag: i32,
1762 oox: u32,
1763 ooy: u32,
1764 osx: u32,
1765 osy: u32,
1766
1767 mode: mode_flag,
1768 fg: i32,
1769 bg: i32,
1770
1771 rlower: u32,
1772 rupper: u32,
1773
1774 rleft: u32,
1775 rright: u32,
1776
1777 event_in: event,
1778 in_: *mut evbuffer,
1779 event_out: event,
1780 out: *mut evbuffer,
1781 timer: event,
1782 discarded: usize,
1783
1784 tio: termios,
1785
1786 cell: grid_cell,
1787 last_cell: grid_cell,
1788
1789 flags: tty_flags,
1790
1791 term: *mut tty_term,
1792
1793 mouse_last_x: u32,
1794 mouse_last_y: u32,
1795 mouse_last_b: u32,
1796 mouse_drag_flag: i32,
1797 mouse_drag_update: Option<unsafe fn(*mut client, *mut mouse_event)>,
1798 mouse_drag_release: Option<unsafe fn(*mut client, *mut mouse_event)>,
1799
1800 key_timer: event,
1801 key_tree: *mut tty_key,
1802}
1803
1804type tty_ctx_redraw_cb = Option<unsafe fn(*const tty_ctx)>;
1805type tty_ctx_set_client_cb = Option<unsafe fn(*mut tty_ctx, *mut client) -> i32>;
1806
1807#[repr(C)]
1808struct tty_ctx {
1809 s: *mut screen,
1810
1811 redraw_cb: tty_ctx_redraw_cb,
1812 set_client_cb: tty_ctx_set_client_cb,
1813 arg: *mut c_void,
1814
1815 cell: *const grid_cell,
1816 wrapped: bool,
1817
1818 num: u32,
1819 ptr: *mut c_void,
1820 ptr2: *mut c_void,
1821
1822 allow_invisible_panes: i32,
1823
1824 ocx: u32,
1828 ocy: u32,
1829
1830 orupper: u32,
1831 orlower: u32,
1832
1833 xoff: u32,
1835 yoff: u32,
1836 rxoff: u32,
1837 ryoff: u32,
1838 sx: u32,
1839 sy: u32,
1840
1841 bg: u32,
1843
1844 defaults: grid_cell,
1846 palette: *const colour_palette,
1847
1848 bigger: i32,
1850 wox: u32,
1851 woy: u32,
1852 wsx: u32,
1853 wsy: u32,
1854}
1855
1856impl_tailq_entry!(message_entry, entry, tailq_entry<message_entry>);
1858#[repr(C)]
1859struct message_entry {
1860 msg: *mut u8,
1861 msg_num: u32,
1862 msg_time: timeval,
1863
1864 entry: tailq_entry<message_entry>,
1865}
1866type message_list = tailq_head<message_entry>;
1867
1868#[repr(i32)]
1870#[derive(Copy, Clone, Eq, PartialEq)]
1871enum args_type {
1872 ARGS_NONE,
1873 ARGS_STRING,
1874 ARGS_COMMANDS,
1875}
1876
1877#[repr(C)]
1878union args_value_union {
1879 string: *mut u8,
1880 cmdlist: *mut cmd_list,
1881}
1882
1883impl_tailq_entry!(args_value, entry, tailq_entry<args_value>);
1884#[repr(C)]
1886struct args_value {
1887 type_: args_type,
1888 union_: args_value_union,
1889 cached: *mut u8,
1890 entry: tailq_entry<args_value>,
1892}
1893type args_tree = rb_head<args_entry>;
1894
1895#[repr(C)]
1897#[derive(Eq, PartialEq)]
1898enum args_parse_type {
1899 ARGS_PARSE_INVALID,
1900 ARGS_PARSE_STRING,
1901 ARGS_PARSE_COMMANDS_OR_STRING,
1902 #[expect(dead_code)]
1903 ARGS_PARSE_COMMANDS,
1904}
1905
1906type args_parse_cb = Option<unsafe fn(*mut args, u32, *mut *mut u8) -> args_parse_type>;
1907#[repr(C)]
1908struct args_parse {
1909 template: SyncCharPtr,
1910 lower: i32,
1911 upper: i32,
1912 cb: args_parse_cb,
1913}
1914
1915impl args_parse {
1916 const fn new(template: &'static CStr, lower: i32, upper: i32, cb: args_parse_cb) -> Self {
1917 Self {
1918 template: SyncCharPtr::new(template),
1919 lower,
1920 upper,
1921 cb,
1922 }
1923 }
1924}
1925
1926#[repr(C)]
1928#[derive(Copy, Clone, Default)]
1929enum cmd_find_type {
1930 #[default]
1931 CMD_FIND_PANE,
1932 CMD_FIND_WINDOW,
1933 CMD_FIND_SESSION,
1934}
1935
1936#[repr(C)]
1937#[derive(Copy, Clone)]
1938struct cmd_find_state {
1939 flags: cmd_find_flags,
1940 current: *mut cmd_find_state,
1941
1942 s: *mut session,
1943 wl: *mut winlink,
1944 w: *mut window,
1945 wp: *mut window_pane,
1946 idx: i32,
1947}
1948
1949bitflags::bitflags! {
1950 #[repr(transparent)]
1952 #[derive(Copy, Clone, Default, Eq, PartialEq)]
1953 struct cmd_find_flags: i32 {
1954 const CMD_FIND_PREFER_UNATTACHED = 0x1;
1955 const CMD_FIND_QUIET = 0x2;
1956 const CMD_FIND_WINDOW_INDEX = 0x4;
1957 const CMD_FIND_DEFAULT_MARKED = 0x8;
1958 const CMD_FIND_EXACT_SESSION = 0x10;
1959 const CMD_FIND_EXACT_WINDOW = 0x20;
1960 const CMD_FIND_CANFAIL = 0x40;
1961 }
1962}
1963
1964#[repr(C)]
1966struct cmd_list {
1967 references: i32,
1968 group: u32,
1969 list: *mut cmds,
1970}
1971
1972#[repr(i32)]
1974#[derive(Copy, Clone, Eq, PartialEq)]
1975enum cmd_retval {
1976 CMD_RETURN_ERROR = -1,
1977 CMD_RETURN_NORMAL = 0,
1978 CMD_RETURN_WAIT,
1979 CMD_RETURN_STOP,
1980}
1981
1982#[repr(i32)]
1984#[derive(Copy, Clone, Default, Eq, PartialEq)]
1985enum cmd_parse_status {
1986 #[default]
1987 CMD_PARSE_ERROR,
1988 CMD_PARSE_SUCCESS,
1989}
1990
1991type cmd_parse_result = Result<*mut cmd_list , *mut u8 >;
1992
1993bitflags::bitflags! {
1994 #[repr(transparent)]
1995 #[derive(Copy, Clone, Eq, PartialEq)]
1996 struct cmd_parse_input_flags: i32 {
1997 const CMD_PARSE_QUIET = 0x1;
1998 const CMD_PARSE_PARSEONLY = 0x2;
1999 const CMD_PARSE_NOALIAS = 0x4;
2000 const CMD_PARSE_VERBOSE = 0x8;
2001 const CMD_PARSE_ONEGROUP = 0x10;
2002 }
2003}
2004
2005#[repr(transparent)]
2006struct AtomicCmdParseInputFlags(std::sync::atomic::AtomicI32);
2007impl From<cmd_parse_input_flags> for AtomicCmdParseInputFlags {
2008 fn from(value: cmd_parse_input_flags) -> Self {
2009 Self(std::sync::atomic::AtomicI32::new(value.bits()))
2010 }
2011}
2012impl AtomicCmdParseInputFlags {
2013 fn intersects(&self, rhs: cmd_parse_input_flags) -> bool {
2014 cmd_parse_input_flags::from_bits(self.0.load(std::sync::atomic::Ordering::SeqCst))
2015 .unwrap()
2016 .intersects(rhs)
2017 }
2018}
2019impl std::ops::BitOrAssign<cmd_parse_input_flags> for &AtomicCmdParseInputFlags {
2020 fn bitor_assign(&mut self, rhs: cmd_parse_input_flags) {
2021 self.0
2022 .fetch_or(rhs.bits(), std::sync::atomic::Ordering::SeqCst);
2023 }
2024}
2025impl std::ops::BitAndAssign<cmd_parse_input_flags> for &AtomicCmdParseInputFlags {
2026 fn bitand_assign(&mut self, rhs: cmd_parse_input_flags) {
2027 self.0
2028 .fetch_and(rhs.bits(), std::sync::atomic::Ordering::SeqCst);
2029 }
2030}
2031
2032#[repr(C)]
2033struct cmd_parse_input<'a> {
2034 flags: AtomicCmdParseInputFlags,
2035
2036 file: Option<&'a str>,
2037 line: AtomicU32, item: *mut cmdq_item,
2040 c: *mut client,
2041 fs: cmd_find_state,
2042}
2043
2044bitflags::bitflags! {
2045 #[repr(transparent)]
2047 #[derive(Copy, Clone, Eq, PartialEq)]
2048 struct cmdq_state_flags: i32 {
2049 const CMDQ_STATE_REPEAT = 0x1;
2050 const CMDQ_STATE_CONTROL = 0x2;
2051 const CMDQ_STATE_NOHOOKS = 0x4;
2052 }
2053}
2054
2055type cmdq_cb = Option<unsafe fn(*mut cmdq_item, *mut c_void) -> cmd_retval>;
2057
2058#[repr(C)]
2060#[derive(Copy, Clone, Default)]
2061struct cmd_entry_flag {
2062 flag: u8,
2063 type_: cmd_find_type,
2064 flags: cmd_find_flags,
2065}
2066
2067impl cmd_entry_flag {
2068 const fn new(flag: u8, type_: cmd_find_type, flags: cmd_find_flags) -> Self {
2069 Self { flag, type_, flags }
2070 }
2071
2072 const fn zeroed() -> Self {
2073 Self {
2074 flag: b'\0',
2075 type_: cmd_find_type::CMD_FIND_PANE,
2076 flags: cmd_find_flags::empty(),
2077 }
2078 }
2079}
2080
2081bitflags::bitflags! {
2082 #[repr(transparent)]
2083 #[derive(Copy, Clone, Eq, PartialEq)]
2084 struct cmd_flag: i32 {
2085 const CMD_STARTSERVER = 0x1;
2086 const CMD_READONLY = 0x2;
2087 const CMD_AFTERHOOK = 0x4;
2088 const CMD_CLIENT_CFLAG = 0x8;
2089 const CMD_CLIENT_TFLAG = 0x10;
2090 const CMD_CLIENT_CANFAIL = 0x20;
2091 }
2092}
2093
2094#[repr(C)]
2096struct cmd_entry {
2097 name: SyncCharPtr,
2098 alias: SyncCharPtr,
2099
2100 args: args_parse,
2101 usage: SyncCharPtr,
2102
2103 source: cmd_entry_flag,
2104 target: cmd_entry_flag,
2105
2106 flags: cmd_flag,
2107
2108 exec: unsafe fn(*mut cmd, *mut cmdq_item) -> cmd_retval,
2109}
2110
2111const STATUS_LINES_LIMIT: usize = 5;
2113#[repr(C)]
2114struct status_line_entry {
2115 expanded: *mut u8,
2116 ranges: style_ranges,
2117}
2118#[repr(C)]
2119struct status_line {
2120 timer: event,
2121
2122 screen: screen,
2123 active: *mut screen,
2124 references: c_int,
2125
2126 style: grid_cell,
2127 entries: [status_line_entry; STATUS_LINES_LIMIT],
2128}
2129
2130enum_try_from!(prompt_type, u32, prompt_type::PROMPT_TYPE_WINDOW_TARGET);
2131const PROMPT_NTYPES: u32 = 4;
2133#[repr(u32)]
2134#[derive(Copy, Clone, Default, Eq, PartialEq)]
2135enum prompt_type {
2136 #[default]
2137 PROMPT_TYPE_COMMAND = 0,
2138 PROMPT_TYPE_SEARCH,
2139 PROMPT_TYPE_TARGET,
2140 PROMPT_TYPE_WINDOW_TARGET,
2141 PROMPT_TYPE_INVALID = 0xff,
2142}
2143
2144type client_file_cb = Option<unsafe fn(*mut client, *mut u8, i32, i32, *mut evbuffer, *mut c_void)>;
2146#[repr(C)]
2147struct client_file {
2148 c: *mut client,
2149 peer: *mut tmuxpeer,
2150 tree: *mut client_files,
2151
2152 references: i32,
2153 stream: i32,
2154
2155 path: *mut u8,
2156 buffer: *mut evbuffer,
2157 event: *mut bufferevent,
2158
2159 fd: i32,
2160 error: i32,
2161 closed: i32,
2162
2163 cb: client_file_cb,
2164 data: *mut c_void,
2165
2166 entry: rb_entry<client_file>,
2167}
2168type client_files = rb_head<client_file>;
2169RB_GENERATE!(client_files, client_file, entry, discr_entry, file_cmp);
2170
2171#[repr(C)]
2173struct client_window {
2174 window: u32,
2175 pane: *mut window_pane,
2176
2177 sx: u32,
2178 sy: u32,
2179
2180 entry: rb_entry<client_window>,
2181}
2182type client_windows = rb_head<client_window>;
2183RB_GENERATE!(
2184 client_windows,
2185 client_window,
2186 entry,
2187 discr_entry,
2188 server_client_window_cmp
2189);
2190
2191const OVERLAY_MAX_RANGES: usize = 3;
2193#[repr(C)]
2194struct overlay_ranges {
2195 px: [u32; OVERLAY_MAX_RANGES],
2196 nx: [u32; OVERLAY_MAX_RANGES],
2197}
2198
2199type prompt_input_cb = Option<unsafe fn(*mut client, NonNull<c_void>, *const u8, i32) -> i32>;
2200type prompt_free_cb = Option<unsafe fn(NonNull<c_void>)>;
2201
2202type overlay_check_cb =
2203 Option<unsafe fn(*mut client, *mut c_void, u32, u32, u32, *mut overlay_ranges)>;
2204type overlay_mode_cb =
2205 Option<unsafe fn(*mut client, *mut c_void, *mut u32, *mut u32) -> *mut screen>;
2206type overlay_draw_cb = Option<unsafe fn(*mut client, *mut c_void, *mut screen_redraw_ctx)>;
2207type overlay_key_cb = Option<unsafe fn(*mut client, *mut c_void, *mut key_event) -> i32>;
2208type overlay_free_cb = Option<unsafe fn(*mut client, *mut c_void)>;
2209type overlay_resize_cb = Option<unsafe fn(*mut client, *mut c_void)>;
2210
2211bitflags::bitflags! {
2212 #[repr(transparent)]
2213 #[derive(Copy, Clone, Eq, PartialEq)]
2214 struct client_flag: u64 {
2215 const TERMINAL = 0x0000000001u64;
2216 const LOGIN = 0x0000000002u64;
2217 const EXIT = 0x0000000004u64;
2218 const REDRAWWINDOW = 0x0000000008u64;
2219 const REDRAWSTATUS = 0x0000000010u64;
2220 const REPEAT = 0x0000000020u64;
2221 const SUSPENDED = 0x0000000040u64;
2222 const ATTACHED = 0x0000000080u64;
2223 const EXITED = 0x0000000100u64;
2224 const DEAD = 0x0000000200u64;
2225 const REDRAWBORDERS = 0x0000000400u64;
2226 const READONLY = 0x0000000800u64;
2227 const NOSTARTSERVER = 0x0000001000u64;
2228 const CONTROL = 0x0000002000u64;
2229 const CONTROLCONTROL = 0x0000004000u64;
2230 const FOCUSED = 0x0000008000u64;
2231 const UTF8 = 0x0000010000u64;
2232 const IGNORESIZE = 0x0000020000u64;
2233 const IDENTIFIED = 0x0000040000u64;
2234 const STATUSFORCE = 0x0000080000u64;
2235 const DOUBLECLICK = 0x0000100000u64;
2236 const TRIPLECLICK = 0x0000200000u64;
2237 const SIZECHANGED = 0x0000400000u64;
2238 const STATUSOFF = 0x0000800000u64;
2239 const REDRAWSTATUSALWAYS = 0x0001000000u64;
2240 const REDRAWOVERLAY = 0x0002000000u64;
2241 const CONTROL_NOOUTPUT = 0x0004000000u64;
2242 const DEFAULTSOCKET = 0x0008000000u64;
2243 const STARTSERVER = 0x0010000000u64;
2244 const REDRAWPANES = 0x0020000000u64;
2245 const NOFORK = 0x0040000000u64;
2246 const ACTIVEPANE = 0x0080000000u64;
2247 const CONTROL_PAUSEAFTER = 0x0100000000u64;
2248 const CONTROL_WAITEXIT = 0x0200000000u64;
2249 const WINDOWSIZECHANGED = 0x0400000000u64;
2250 const CLIPBOARDBUFFER = 0x0800000000u64;
2251 const BRACKETPASTING = 0x1000000000u64;
2252 }
2253}
2254
2255const CLIENT_ALLREDRAWFLAGS: client_flag = client_flag::REDRAWWINDOW
2256 .union(client_flag::REDRAWSTATUS)
2257 .union(client_flag::REDRAWSTATUSALWAYS)
2258 .union(client_flag::REDRAWBORDERS)
2259 .union(client_flag::REDRAWOVERLAY)
2260 .union(client_flag::REDRAWPANES);
2261const CLIENT_UNATTACHEDFLAGS: client_flag = client_flag::DEAD
2262 .union(client_flag::SUSPENDED)
2263 .union(client_flag::EXIT);
2264const CLIENT_NODETACHFLAGS: client_flag = client_flag::DEAD.union(client_flag::EXIT);
2265const CLIENT_NOSIZEFLAGS: client_flag = client_flag::DEAD
2266 .union(client_flag::SUSPENDED)
2267 .union(client_flag::EXIT);
2268
2269const PROMPT_SINGLE: i32 = 0x1;
2270const PROMPT_NUMERIC: i32 = 0x2;
2271const PROMPT_INCREMENTAL: i32 = 0x4;
2272const PROMPT_NOFORMAT: i32 = 0x8;
2273const PROMPT_KEY: i32 = 0x8;
2274
2275impl_tailq_entry!(client, entry, tailq_entry<client>);
2276#[repr(C)]
2277struct client {
2278 name: *const u8,
2279 peer: *mut tmuxpeer,
2280 queue: *mut cmdq_list,
2281
2282 windows: client_windows,
2283
2284 control_state: *mut control_state,
2285 pause_age: c_uint,
2286
2287 pid: pid_t,
2288 fd: c_int,
2289 out_fd: c_int,
2290 event: event,
2291 retval: c_int,
2292
2293 creation_time: timeval,
2294 activity_time: timeval,
2295
2296 environ: *mut environ,
2297 jobs: *mut format_job_tree,
2298
2299 title: *mut u8,
2300 path: *mut u8,
2301 cwd: *const u8,
2302
2303 term_name: *mut u8,
2304 term_features: c_int,
2305 term_type: *mut u8,
2306 term_caps: *mut *mut u8,
2307 term_ncaps: c_uint,
2308
2309 ttyname: *mut u8,
2310 tty: tty,
2311
2312 written: usize,
2313 discarded: usize,
2314 redraw: usize,
2315
2316 repeat_timer: event,
2317
2318 click_timer: event,
2319 click_button: c_uint,
2320 click_event: mouse_event,
2321
2322 status: status_line,
2323
2324 flags: client_flag,
2325
2326 exit_type: exit_type,
2327 exit_msgtype: msgtype,
2328 exit_session: *mut u8,
2329 exit_message: *mut u8,
2330
2331 keytable: *mut key_table,
2332
2333 redraw_panes: u64,
2334
2335 message_ignore_keys: c_int,
2336 message_ignore_styles: c_int,
2337 message_string: *mut u8,
2338 message_timer: event,
2339
2340 prompt_string: *mut u8,
2341 prompt_buffer: *mut utf8_data,
2342 prompt_last: *mut u8,
2343 prompt_index: usize,
2344 prompt_inputcb: prompt_input_cb,
2345 prompt_freecb: prompt_free_cb,
2346 prompt_data: *mut c_void,
2347 prompt_hindex: [c_uint; 4],
2348 prompt_mode: prompt_mode,
2349 prompt_saved: *mut utf8_data,
2350
2351 prompt_flags: c_int,
2352 prompt_type: prompt_type,
2353 prompt_cursor: c_int,
2354
2355 session: *mut session,
2356 last_session: *mut session,
2357
2358 references: c_int,
2359
2360 pan_window: *mut c_void,
2361 pan_ox: c_uint,
2362 pan_oy: c_uint,
2363
2364 overlay_check: overlay_check_cb,
2365 overlay_mode: overlay_mode_cb,
2366 overlay_draw: overlay_draw_cb,
2367 overlay_key: overlay_key_cb,
2368 overlay_free: overlay_free_cb,
2369 overlay_resize: overlay_resize_cb,
2370 overlay_data: *mut c_void,
2371 overlay_timer: event,
2372
2373 files: client_files,
2374
2375 clipboard_panes: *mut c_uint,
2376 clipboard_npanes: c_uint,
2377
2378 entry: tailq_entry<client>,
2380}
2381type clients = tailq_head<client>;
2382
2383#[repr(i32)]
2385enum control_sub_type {
2386 CONTROL_SUB_SESSION,
2387 CONTROL_SUB_PANE,
2388 CONTROL_SUB_ALL_PANES,
2389 CONTROL_SUB_WINDOW,
2390 CONTROL_SUB_ALL_WINDOWS,
2391}
2392
2393const KEY_BINDING_REPEAT: i32 = 0x1;
2394
2395#[repr(C)]
2397struct key_binding {
2398 key: key_code,
2399 cmdlist: *mut cmd_list,
2400 note: *mut u8,
2401
2402 flags: i32,
2403
2404 entry: rb_entry<key_binding>,
2405}
2406type key_bindings = rb_head<key_binding>;
2407
2408#[repr(C)]
2409struct key_table {
2410 name: *mut u8,
2411 activity_time: timeval,
2412 key_bindings: key_bindings,
2413 default_key_bindings: key_bindings,
2414
2415 references: u32,
2416
2417 entry: rb_entry<key_table>,
2418}
2419type key_tables = rb_head<key_table>;
2420
2421type options_array = rb_head<options_array_item>;
2423
2424#[repr(C)]
2425#[derive(Copy, Clone)]
2426union options_value {
2427 string: *mut u8,
2428 number: c_longlong,
2429 style: style,
2430 array: options_array,
2431 cmdlist: *mut cmd_list,
2432}
2433
2434#[repr(i32)]
2436#[derive(Clone, Copy, PartialEq, Eq)]
2437enum options_table_type {
2438 OPTIONS_TABLE_STRING,
2439 OPTIONS_TABLE_NUMBER,
2440 OPTIONS_TABLE_KEY,
2441 OPTIONS_TABLE_COLOUR,
2442 OPTIONS_TABLE_FLAG,
2443 OPTIONS_TABLE_CHOICE,
2444 OPTIONS_TABLE_COMMAND,
2445}
2446
2447const OPTIONS_TABLE_NONE: i32 = 0;
2448const OPTIONS_TABLE_SERVER: i32 = 0x1;
2449const OPTIONS_TABLE_SESSION: i32 = 0x2;
2450const OPTIONS_TABLE_WINDOW: i32 = 0x4;
2451const OPTIONS_TABLE_PANE: i32 = 0x8;
2452
2453const OPTIONS_TABLE_IS_ARRAY: i32 = 0x1;
2454const OPTIONS_TABLE_IS_HOOK: i32 = 0x2;
2455const OPTIONS_TABLE_IS_STYLE: i32 = 0x4;
2456
2457#[repr(C)]
2458struct options_table_entry {
2459 name: *const u8,
2460 alternative_name: *mut u8,
2461 type_: options_table_type,
2462 scope: i32,
2463 flags: i32,
2464 minimum: u32,
2465 maximum: u32,
2466
2467 choices: *const *const u8,
2468
2469 default_str: Option<&'static str>,
2470 default_num: c_longlong,
2471 default_arr: *const *const u8,
2472
2473 separator: *const u8,
2474 pattern: *const u8,
2475
2476 text: *const u8,
2477 unit: *const u8,
2478}
2479
2480#[repr(C)]
2481struct options_name_map_str {
2482 from: &'static str,
2483 to: &'static str,
2484}
2485impl options_name_map_str {
2486 const fn new(from: &'static str, to: &'static str) -> Self {
2487 Self { from, to }
2488 }
2489}
2490
2491#[repr(C)]
2492struct options_name_map {
2493 from: *const u8,
2494 to: *const u8,
2495}
2496impl options_name_map {
2497 const fn new(from: *const u8, to: *const u8) -> Self {
2498 Self { from, to }
2499 }
2500}
2501
2502const CMD_TARGET_PANE_USAGE: &CStr = c"[-t target-pane]";
2504const CMD_TARGET_WINDOW_USAGE: &CStr = c"[-t target-window]";
2505const CMD_BUFFER_USAGE: &CStr = c"[-b buffer-name]";
2512
2513bitflags::bitflags! {
2514 #[repr(transparent)]
2515 #[derive(Copy, Clone, Eq, PartialEq)]
2516 struct spawn_flags: i32 {
2517 const SPAWN_KILL = 0x1;
2518 const SPAWN_DETACHED = 0x2;
2519 const SPAWN_RESPAWN = 0x4;
2520 const SPAWN_BEFORE = 0x8;
2521 const SPAWN_NONOTIFY = 0x10;
2522 const SPAWN_FULLSIZE = 0x20;
2523 const SPAWN_EMPTY = 0x40;
2524 const SPAWN_ZOOM = 0x80;
2525 }
2526}
2527
2528const SPAWN_KILL: spawn_flags = spawn_flags::SPAWN_KILL;
2530const SPAWN_DETACHED: spawn_flags = spawn_flags::SPAWN_DETACHED;
2531const SPAWN_RESPAWN: spawn_flags = spawn_flags::SPAWN_RESPAWN;
2532const SPAWN_BEFORE: spawn_flags = spawn_flags::SPAWN_BEFORE;
2533const SPAWN_NONOTIFY: spawn_flags = spawn_flags::SPAWN_NONOTIFY;
2534const SPAWN_FULLSIZE: spawn_flags = spawn_flags::SPAWN_FULLSIZE;
2535const SPAWN_EMPTY: spawn_flags = spawn_flags::SPAWN_EMPTY;
2536const SPAWN_ZOOM: spawn_flags = spawn_flags::SPAWN_ZOOM;
2537
2538#[repr(C)]
2540struct spawn_context {
2541 item: *mut cmdq_item,
2542
2543 s: *mut session,
2544 wl: *mut winlink,
2545 tc: *mut client,
2546
2547 wp0: *mut window_pane,
2548 lc: *mut layout_cell,
2549
2550 name: *const u8,
2551 argv: *mut *mut u8,
2552 argc: i32,
2553 environ: *mut environ,
2554
2555 idx: i32,
2556 cwd: *const u8,
2557
2558 flags: spawn_flags,
2559}
2560
2561#[repr(C)]
2563struct mode_tree_sort_criteria {
2564 field: u32,
2565 reversed: bool,
2566}
2567
2568const WINDOW_MINIMUM: u32 = PANE_MINIMUM;
2569const WINDOW_MAXIMUM: u32 = 10_000;
2570
2571#[repr(i32)]
2572enum exit_type {
2573 #[expect(dead_code)]
2574 CLIENT_EXIT_RETURN,
2575 CLIENT_EXIT_SHUTDOWN,
2576 CLIENT_EXIT_DETACH,
2577}
2578
2579#[repr(i32)]
2580#[derive(Copy, Clone, Eq, PartialEq)]
2581enum prompt_mode {
2582 PROMPT_ENTRY,
2583 PROMPT_COMMAND,
2584}
2585
2586mod tmux;
2587
2588pub use crate::tmux::tmux_main;
2589use crate::tmux::{
2590 GLOBAL_ENVIRON, GLOBAL_OPTIONS, GLOBAL_S_OPTIONS, GLOBAL_W_OPTIONS, PTM_FD, SHELL_COMMAND,
2591 SOCKET_PATH, START_TIME, checkshell_, find_cwd, find_home, get_timer, getversion, setblocking,
2592 shell_argv0,
2593};
2594
2595mod proc;
2596use crate::proc::{
2597 proc_add_peer, proc_clear_signals, proc_exit, proc_flush_peer, proc_fork_and_daemon,
2598 proc_get_peer_uid, proc_kill_peer, proc_loop, proc_remove_peer, proc_send, proc_set_signals,
2599 proc_start, proc_toggle_log, tmuxpeer, tmuxproc,
2600};
2601
2602mod cfg_;
2603use crate::cfg_::{
2604 CFG_CLIENT, CFG_FILES, CFG_FINISHED, CFG_QUIET, cfg_print_causes, cfg_show_causes,
2605 load_cfg_from_buffer, start_cfg,
2606};
2607
2608mod paste;
2609use crate::paste::{
2610 paste_add, paste_buffer, paste_buffer_created, paste_buffer_data, paste_buffer_data_,
2611 paste_buffer_name, paste_buffer_order, paste_free, paste_get_name, paste_get_top,
2612 paste_is_empty, paste_make_sample, paste_rename, paste_replace, paste_set, paste_walk,
2613};
2614
2615mod format;
2616use crate::format::format_add;
2617use crate::format::{
2618 FORMAT_NONE, FORMAT_PANE, FORMAT_WINDOW, format_add_cb, format_add_tv, format_create,
2619 format_create_defaults, format_create_from_state, format_create_from_target, format_defaults,
2620 format_defaults_pane, format_defaults_paste_buffer, format_defaults_window, format_each,
2621 format_expand, format_expand_time, format_flags, format_free, format_get_pane,
2622 format_grid_hyperlink, format_grid_line, format_grid_word, format_job_tree, format_log_debug,
2623 format_lost_client, format_merge, format_pretty_time, format_single, format_single_from_state,
2624 format_single_from_target, format_skip, format_tidy_jobs, format_tree, format_true,
2625};
2626
2627mod format_draw_;
2628use crate::format_draw_::{format_draw, format_trim_left, format_trim_right, format_width};
2629
2630mod notify;
2631use crate::notify::{
2632 notify_client, notify_hook, notify_pane, notify_paste_buffer, notify_session,
2633 notify_session_window, notify_window, notify_winlink,
2634};
2635
2636mod options_;
2637use crate::options_::options_set_string;
2638use crate::options_::{
2639 options, options_array_assign, options_array_clear, options_array_first, options_array_get,
2640 options_array_item, options_array_item_index, options_array_item_value, options_array_next,
2641 options_array_set, options_create, options_default, options_default_to_string, options_empty,
2642 options_entry, options_first, options_free, options_from_string, options_get, options_get_,
2643 options_get_number, options_get_number_, options_get_only, options_get_parent,
2644 options_get_string, options_get_string_, options_is_array, options_is_string, options_match,
2645 options_name, options_next, options_owner, options_parse_get, options_push_changes,
2646 options_remove_or_default, options_scope_from_flags, options_scope_from_name,
2647 options_set_number, options_set_parent, options_string_to_style, options_table_entry,
2648 options_to_string,
2649};
2650
2651mod options_table;
2652use crate::options_table::{OPTIONS_OTHER_NAMES, OPTIONS_TABLE};
2653
2654bitflags::bitflags! {
2655 #[repr(transparent)]
2656 #[derive(Copy, Clone, Eq, PartialEq)]
2657 struct job_flag: i32 {
2658 const JOB_NOWAIT = 1;
2659 const JOB_KEEPWRITE = 2;
2660 const JOB_PTY = 4;
2661 const JOB_DEFAULTSHELL = 8;
2662 }
2663}
2664mod job_;
2665use crate::job_::{
2666 job, job_check_died, job_free, job_get_data, job_get_event, job_get_status, job_kill_all,
2667 job_print_summary, job_resize, job_run, job_still_running, job_transfer,
2668};
2669
2670mod environ_;
2671use crate::environ_::{
2672 environ, environ_clear, environ_copy, environ_create, environ_find, environ_first,
2673 environ_for_session, environ_free, environ_next, environ_push, environ_put, environ_unset,
2674 environ_update,
2675};
2676use crate::environ_::{environ_log, environ_set};
2677
2678mod tty_;
2679use crate::tty_::{
2680 tty_attributes, tty_cell, tty_clipboard_query, tty_close, tty_cmd_alignmenttest, tty_cmd_cell,
2681 tty_cmd_cells, tty_cmd_clearcharacter, tty_cmd_clearendofscreen, tty_cmd_clearscreen,
2682 tty_cmd_clearstartofscreen, tty_cmd_deletecharacter, tty_cmd_deleteline,
2683 tty_cmd_insertcharacter, tty_cmd_insertline, tty_cmd_rawstring, tty_cmd_reverseindex,
2684 tty_cmd_scrolldown, tty_cmd_scrollup, tty_cmd_setselection, tty_cmd_syncstart, tty_create_log,
2685 tty_cursor, tty_default_colours, tty_draw_line, tty_free, tty_init, tty_margin_off, tty_open,
2686 tty_putc, tty_putcode, tty_putn, tty_puts, tty_raw, tty_region_off, tty_repeat_requests,
2687 tty_reset, tty_resize, tty_send_requests, tty_set_path, tty_set_selection, tty_set_size,
2688 tty_set_title, tty_start_tty, tty_stop_tty, tty_sync_end, tty_sync_start,
2689 tty_update_client_offset, tty_update_features, tty_update_mode, tty_update_window_offset,
2690 tty_window_bigger, tty_window_offset, tty_write,
2691};
2692
2693mod tty_term_;
2694use crate::tty_term_::{
2695 TTY_TERMS, tty_code, tty_term_apply, tty_term_apply_overrides, tty_term_create,
2696 tty_term_describe, tty_term_flag, tty_term_free, tty_term_free_list, tty_term_has,
2697 tty_term_ncodes, tty_term_number, tty_term_read_list, tty_term_string, tty_term_string_i,
2698 tty_term_string_ii, tty_term_string_iii, tty_term_string_s, tty_term_string_ss,
2699};
2700
2701mod tty_features;
2702use crate::tty_features::{
2703 tty_add_features, tty_apply_features, tty_default_features, tty_get_features,
2704};
2705
2706mod tty_acs;
2707use crate::tty_acs::{
2708 tty_acs_double_borders, tty_acs_get, tty_acs_heavy_borders, tty_acs_needed,
2709 tty_acs_reverse_get, tty_acs_rounded_borders,
2710};
2711
2712mod tty_keys;
2713use crate::tty_keys::{tty_key, tty_keys_build, tty_keys_colours, tty_keys_free, tty_keys_next};
2714
2715mod arguments;
2716
2717unsafe fn args_get_(args: *mut args, flag: char) -> *const u8 {
2719 debug_assert!(flag.is_ascii());
2720 unsafe { args_get(args, flag as u8) }
2721}
2722
2723use crate::arguments::{
2724 args, args_command_state, args_copy, args_count, args_create, args_entry, args_escape,
2725 args_first, args_first_value, args_free, args_free_value, args_free_values, args_from_vector,
2726 args_get, args_has, args_has_count, args_make_commands, args_make_commands_free,
2727 args_make_commands_get_command, args_make_commands_now, args_make_commands_prepare, args_next,
2728 args_next_value, args_parse, args_percentage, args_percentage_and_expand, args_print, args_set,
2729 args_string, args_string_percentage, args_strtonum, args_strtonum_and_expand, args_to_vector,
2730 args_value, args_values,
2731};
2732
2733mod cmd_;
2734use crate::cmd_::cmd_attach_session::cmd_attach_session;
2735use crate::cmd_::cmd_find::{
2736 cmd_find_best_client, cmd_find_clear_state, cmd_find_client, cmd_find_copy_state,
2737 cmd_find_empty_state, cmd_find_from_client, cmd_find_from_mouse, cmd_find_from_nothing,
2738 cmd_find_from_pane, cmd_find_from_session, cmd_find_from_session_window, cmd_find_from_window,
2739 cmd_find_from_winlink, cmd_find_from_winlink_pane, cmd_find_target, cmd_find_valid_state,
2740};
2741use crate::cmd_::cmd_log_argv;
2742use crate::cmd_::{
2743 CMD_TABLE, cmd, cmd_append_argv, cmd_copy_argv, cmd_free_argv, cmd_get_alias, cmd_get_args,
2744 cmd_get_entry, cmd_get_group, cmd_get_source, cmd_list_all_have, cmd_list_any_have,
2745 cmd_list_append, cmd_list_append_all, cmd_list_copy, cmd_list_first, cmd_list_free,
2746 cmd_list_move, cmd_list_new, cmd_list_next, cmd_list_print, cmd_mouse_at, cmd_mouse_pane,
2747 cmd_mouse_window, cmd_pack_argv, cmd_parse, cmd_print, cmd_stringify_argv,
2748 cmd_template_replace, cmd_unpack_argv, cmds,
2749};
2750
2751mod cmd_parse;
2752use crate::cmd_::cmd_queue::{
2753 cmdq_add_format, cmdq_add_formats, cmdq_append, cmdq_continue, cmdq_copy_state, cmdq_error,
2754 cmdq_free, cmdq_free_state, cmdq_get_callback, cmdq_get_client, cmdq_get_command,
2755 cmdq_get_current, cmdq_get_error, cmdq_get_event, cmdq_get_flags, cmdq_get_name,
2756 cmdq_get_source, cmdq_get_state, cmdq_get_target, cmdq_get_target_client, cmdq_guard,
2757 cmdq_insert_after, cmdq_insert_hook, cmdq_item, cmdq_list, cmdq_merge_formats, cmdq_new,
2758 cmdq_new_state, cmdq_next, cmdq_print, cmdq_print_data, cmdq_running, cmdq_state,
2759};
2760use crate::cmd_::cmd_wait_for::cmd_wait_for_flush;
2761use crate::cmd_parse::{
2762 cmd_parse_and_append, cmd_parse_from_arguments, cmd_parse_from_buffer, cmd_parse_from_file,
2763 cmd_parse_from_string, cmd_parse_state, *,
2764};
2765
2766mod client_;
2767use crate::client_::client_main;
2768
2769mod key_bindings_;
2770use crate::key_bindings_::{
2771 key_bindings_add, key_bindings_dispatch, key_bindings_first, key_bindings_first_table,
2772 key_bindings_get, key_bindings_get_default, key_bindings_get_table, key_bindings_init,
2773 key_bindings_next, key_bindings_next_table, key_bindings_remove, key_bindings_remove_table,
2774 key_bindings_reset, key_bindings_unref_table,
2775};
2776
2777mod key_string;
2778use crate::key_string::{key_string_lookup_key, key_string_lookup_string};
2779
2780mod alerts;
2781use crate::alerts::{alerts_check_session, alerts_queue, alerts_reset_all};
2782
2783mod file;
2784use crate::file::{
2785 file_can_print, file_cancel, file_cmp, file_error, file_fire_done, file_print,
2786 file_print_buffer, file_read, file_read_cancel, file_read_data, file_read_done, file_read_open,
2787 file_write, file_write_close, file_write_data, file_write_left, file_write_open,
2788 file_write_ready,
2789};
2790
2791mod server;
2792use crate::server::{
2793 CLIENTS, CURRENT_TIME, MARKED_PANE, SERVER_PROC, server_add_accept, server_add_message,
2794 server_check_marked, server_clear_marked, server_is_marked, server_set_marked, server_start,
2795 server_update_socket,
2796};
2797
2798mod server_client;
2799use crate::server_client::{
2800 server_client_add_client_window, server_client_check_nested, server_client_clear_overlay,
2801 server_client_create, server_client_detach, server_client_exec,
2802 server_client_get_client_window, server_client_get_cwd, server_client_get_flags,
2803 server_client_get_key_table, server_client_get_pane, server_client_handle_key,
2804 server_client_how_many, server_client_loop, server_client_lost, server_client_open,
2805 server_client_overlay_range, server_client_print, server_client_remove_pane,
2806 server_client_set_flags, server_client_set_key_table, server_client_set_overlay,
2807 server_client_set_pane, server_client_set_session, server_client_suspend, server_client_unref,
2808 server_client_window_cmp,
2809};
2810
2811mod server_fn;
2812use crate::server_fn::{
2813 server_check_unattached, server_destroy_pane, server_destroy_session, server_kill_pane,
2814 server_kill_window, server_link_window, server_lock, server_lock_client, server_lock_session,
2815 server_redraw_client, server_redraw_session, server_redraw_session_group, server_redraw_window,
2816 server_redraw_window_borders, server_renumber_all, server_status_client, server_status_session,
2817 server_status_session_group, server_status_window, server_unlink_window, server_unzoom_window,
2818};
2819
2820mod status;
2821use crate::status::{
2822 STATUS_PROMPT_HLIST, STATUS_PROMPT_HSIZE, status_at_line, status_free, status_get_range,
2823 status_init, status_line_size, status_message_clear, status_message_redraw, status_message_set,
2824 status_prompt_clear, status_prompt_key, status_prompt_load_history, status_prompt_redraw,
2825 status_prompt_save_history, status_prompt_set, status_prompt_type, status_prompt_type_string,
2826 status_prompt_update, status_redraw, status_timer_start, status_timer_start_all,
2827 status_update_cache,
2828};
2829
2830mod resize;
2831use crate::resize::{
2832 default_window_size, recalculate_size, recalculate_sizes, recalculate_sizes_now, resize_window,
2833};
2834
2835mod input;
2836use crate::input::{
2837 input_ctx, input_free, input_init, input_parse_buffer, input_parse_pane, input_parse_screen,
2838 input_pending, input_reply_clipboard, input_reset,
2839};
2840
2841mod input_keys;
2842use crate::input_keys::{input_key, input_key_build, input_key_get_mouse, input_key_pane};
2843
2844mod colour;
2845use crate::colour::{
2846 colour_256to16, colour_find_rgb, colour_force_rgb, colour_fromstring, colour_fromstring_,
2847 colour_join_rgb, colour_palette_clear, colour_palette_free, colour_palette_from_option,
2848 colour_palette_get, colour_palette_init, colour_palette_set, colour_parse_x11,
2849 colour_split_rgb, colour_tostring,
2850};
2851
2852mod attributes;
2853use crate::attributes::{attributes_fromstring, attributes_tostring};
2854
2855mod grid_;
2856use crate::grid_::{
2857 GRID_DEFAULT_CELL, grid_adjust_lines, grid_cells_equal, grid_cells_look_equal, grid_clear,
2858 grid_clear_history, grid_clear_lines, grid_collect_history, grid_compare, grid_create,
2859 grid_destroy, grid_duplicate_lines, grid_empty_line, grid_get_cell, grid_get_line,
2860 grid_line_length, grid_move_cells, grid_move_lines, grid_peek_line, grid_reflow,
2861 grid_remove_history, grid_scroll_history, grid_scroll_history_region, grid_set_cell,
2862 grid_set_cells, grid_set_padding, grid_string_cells, grid_unwrap_position, grid_wrap_position,
2863};
2864
2865mod grid_reader_;
2866use crate::grid_reader_::{
2867 grid_reader_cursor_back_to_indentation, grid_reader_cursor_end_of_line,
2868 grid_reader_cursor_jump, grid_reader_cursor_jump_back, grid_reader_cursor_left,
2869 grid_reader_cursor_next_word, grid_reader_cursor_next_word_end,
2870 grid_reader_cursor_previous_word, grid_reader_cursor_right, grid_reader_cursor_start_of_line,
2871 grid_reader_get_cursor, grid_reader_in_set, grid_reader_start,
2872};
2873
2874mod grid_view;
2875use crate::grid_view::{
2876 grid_view_clear, grid_view_clear_history, grid_view_delete_cells, grid_view_delete_lines,
2877 grid_view_delete_lines_region, grid_view_get_cell, grid_view_insert_cells,
2878 grid_view_insert_lines, grid_view_insert_lines_region, grid_view_scroll_region_down,
2879 grid_view_scroll_region_up, grid_view_set_cell, grid_view_set_cells, grid_view_set_padding,
2880 grid_view_string_cells,
2881};
2882
2883mod screen_write;
2884use crate::screen_write::{
2885 screen_write_alignmenttest, screen_write_alternateoff, screen_write_alternateon,
2886 screen_write_backspace, screen_write_box, screen_write_carriagereturn, screen_write_cell,
2887 screen_write_citem, screen_write_clearcharacter, screen_write_clearendofline,
2888 screen_write_clearendofscreen, screen_write_clearhistory, screen_write_clearline,
2889 screen_write_clearscreen, screen_write_clearstartofline, screen_write_clearstartofscreen,
2890 screen_write_cline, screen_write_collect_add, screen_write_collect_end,
2891 screen_write_cursordown, screen_write_cursorleft, screen_write_cursormove,
2892 screen_write_cursorright, screen_write_cursorup, screen_write_deletecharacter,
2893 screen_write_deleteline, screen_write_fast_copy, screen_write_free_list,
2894 screen_write_fullredraw, screen_write_hline, screen_write_insertcharacter,
2895 screen_write_insertline, screen_write_linefeed, screen_write_make_list, screen_write_menu,
2896 screen_write_mode_clear, screen_write_mode_set, screen_write_preview, screen_write_putc,
2897 screen_write_rawstring, screen_write_reset, screen_write_reverseindex, screen_write_scrolldown,
2898 screen_write_scrollregion, screen_write_scrollup, screen_write_setselection,
2899 screen_write_start, screen_write_start_callback, screen_write_start_pane, screen_write_stop,
2900 screen_write_vline,
2901};
2902use crate::screen_write::{
2903 screen_write_nputs, screen_write_puts, screen_write_strlen, screen_write_text,
2904 screen_write_vnputs, screen_write_vnputs_,
2905};
2906
2907mod screen_redraw;
2908use crate::screen_redraw::{screen_redraw_pane, screen_redraw_screen};
2909
2910mod screen_;
2911use crate::screen_::{
2912 screen_alternate_off, screen_alternate_on, screen_check_selection, screen_clear_selection,
2913 screen_free, screen_hide_selection, screen_init, screen_mode_to_string, screen_pop_title,
2914 screen_push_title, screen_reinit, screen_reset_hyperlinks, screen_reset_tabs, screen_resize,
2915 screen_resize_cursor, screen_sel, screen_select_cell, screen_set_cursor_colour,
2916 screen_set_cursor_style, screen_set_path, screen_set_selection, screen_set_title,
2917 screen_titles,
2918};
2919
2920mod window_;
2921use crate::window_::{
2922 ALL_WINDOW_PANES, WINDOWS, window_add_pane, window_add_ref, window_count_panes, window_create,
2923 window_destroy_panes, window_find_by_id, window_find_by_id_str, window_find_string,
2924 window_get_active_at, window_has_pane, window_lost_pane, window_pane_at_index,
2925 window_pane_default_cursor, window_pane_destroy_ready, window_pane_exited,
2926 window_pane_find_by_id, window_pane_find_by_id_str, window_pane_find_down,
2927 window_pane_find_left, window_pane_find_right, window_pane_find_up, window_pane_get_new_data,
2928 window_pane_index, window_pane_key, window_pane_mode, window_pane_next_by_number,
2929 window_pane_previous_by_number, window_pane_reset_mode, window_pane_reset_mode_all,
2930 window_pane_resize, window_pane_search, window_pane_send_resize, window_pane_set_event,
2931 window_pane_set_mode, window_pane_stack_remove, window_pane_start_input,
2932 window_pane_update_used_data, window_pane_visible, window_pop_zoom, window_printable_flags,
2933 window_push_zoom, window_redraw_active_switch, window_remove_pane, window_remove_ref,
2934 window_resize, window_set_active_pane, window_set_fill_character, window_set_name,
2935 window_unzoom, window_update_activity, window_update_focus, window_zoom, winlink_add,
2936 winlink_clear_flags, winlink_count, winlink_find_by_index, winlink_find_by_window,
2937 winlink_find_by_window_id, winlink_next, winlink_next_by_number, winlink_previous,
2938 winlink_previous_by_number, winlink_remove, winlink_set_window, winlink_shuffle_up,
2939 winlink_stack_push, winlink_stack_remove,
2940};
2941
2942mod layout;
2943use crate::layout::{
2944 layout_assign_pane, layout_close_pane, layout_count_cells, layout_create_cell,
2945 layout_destroy_cell, layout_fix_offsets, layout_fix_panes, layout_free, layout_free_cell,
2946 layout_init, layout_make_leaf, layout_make_node, layout_print_cell, layout_resize,
2947 layout_resize_adjust, layout_resize_layout, layout_resize_pane, layout_resize_pane_to,
2948 layout_search_by_border, layout_set_size, layout_split_pane, layout_spread_cell,
2949 layout_spread_out,
2950};
2951
2952mod layout_custom;
2953use crate::layout_custom::{layout_dump, layout_parse};
2954
2955mod layout_set;
2956use crate::layout_set::{
2957 layout_set_lookup, layout_set_next, layout_set_previous, layout_set_select,
2958};
2959
2960mod mode_tree;
2961use crate::mode_tree::{
2962 mode_tree_add, mode_tree_build, mode_tree_collapse_current, mode_tree_count_tagged,
2963 mode_tree_data, mode_tree_down, mode_tree_draw, mode_tree_draw_as_parent,
2964 mode_tree_each_tagged, mode_tree_expand, mode_tree_expand_current, mode_tree_free,
2965 mode_tree_get_current, mode_tree_get_current_name, mode_tree_item, mode_tree_key,
2966 mode_tree_no_tag, mode_tree_remove, mode_tree_resize, mode_tree_run_command,
2967 mode_tree_set_current, mode_tree_start, mode_tree_up, mode_tree_zoom,
2968};
2969
2970mod window_buffer;
2971use crate::window_buffer::WINDOW_BUFFER_MODE;
2972
2973mod window_tree;
2974use crate::window_tree::WINDOW_TREE_MODE;
2975
2976mod window_clock;
2977use crate::window_clock::{WINDOW_CLOCK_MODE, WINDOW_CLOCK_TABLE};
2978
2979mod window_client;
2980use crate::window_client::WINDOW_CLIENT_MODE;
2981
2982mod window_copy;
2983use crate::window_copy::window_copy_add;
2984use crate::window_copy::{
2985 WINDOW_COPY_MODE, WINDOW_VIEW_MODE, window_copy_get_line, window_copy_get_word,
2986 window_copy_pagedown, window_copy_pageup, window_copy_start_drag,
2987};
2988
2989mod window_customize;
2990use crate::window_customize::WINDOW_CUSTOMIZE_MODE;
2991
2992mod names;
2993use crate::names::{check_window_name, default_window_name, parse_window_name};
2994
2995mod control;
2996use crate::control::control_write;
2997use crate::control::{
2998 control_add_sub, control_all_done, control_continue_pane, control_discard, control_pane_offset,
2999 control_pause_pane, control_ready, control_remove_sub, control_reset_offsets,
3000 control_set_pane_off, control_set_pane_on, control_start, control_state, control_stop,
3001 control_write_output,
3002};
3003
3004mod control_notify;
3005use crate::control_notify::{
3006 control_notify_client_detached, control_notify_client_session_changed,
3007 control_notify_pane_mode_changed, control_notify_paste_buffer_changed,
3008 control_notify_paste_buffer_deleted, control_notify_session_closed,
3009 control_notify_session_created, control_notify_session_renamed,
3010 control_notify_session_window_changed, control_notify_window_layout_changed,
3011 control_notify_window_linked, control_notify_window_pane_changed,
3012 control_notify_window_renamed, control_notify_window_unlinked,
3013};
3014
3015mod session_;
3016use crate::session_::{
3017 NEXT_SESSION_ID, SESSIONS, session_add_ref, session_alive, session_attach, session_check_name,
3018 session_create, session_destroy, session_detach, session_find, session_find_by_id,
3019 session_find_by_id_str, session_group_add, session_group_attached_count,
3020 session_group_contains, session_group_count, session_group_find, session_group_new,
3021 session_group_synchronize_from, session_group_synchronize_to, session_has, session_is_linked,
3022 session_last, session_next, session_next_session, session_previous, session_previous_session,
3023 session_remove_ref, session_renumber_windows, session_select, session_set_current,
3024 session_update_activity,
3025};
3026
3027mod utf8;
3028use crate::utf8::{
3029 utf8_append, utf8_build_one, utf8_copy, utf8_cstrhas, utf8_cstrwidth, utf8_from_data,
3030 utf8_fromcstr, utf8_fromwc, utf8_in_table, utf8_isvalid, utf8_open, utf8_padcstr,
3031 utf8_rpadcstr, utf8_sanitize, utf8_set, utf8_stravis, utf8_stravisx, utf8_strlen, utf8_strvis,
3032 utf8_strwidth, utf8_to_data, utf8_tocstr, utf8_towc,
3033};
3034
3035mod osdep;
3036use crate::osdep::{osdep_event_init, osdep_get_cwd, osdep_get_name};
3037
3038mod utf8_combined;
3039use crate::utf8_combined::{utf8_has_zwj, utf8_is_modifier, utf8_is_vs, utf8_is_zwj};
3040
3041#[macro_use] mod log;
3043use crate::log::{fatal, fatalx, log_add_level, log_close, log_get_level, log_open, log_toggle};
3044use crate::log::{fatalx_, log_debug};
3045
3046bitflags::bitflags! {
3047 #[repr(transparent)]
3048 #[derive(Copy, Clone, Eq, PartialEq)]
3049 struct menu_flags: i32 {
3050 const MENU_NOMOUSE = 0x1;
3051 const MENU_TAB = 0x2;
3052 const MENU_STAYOPEN = 0x4;
3053 }
3054}
3055const MENU_NOMOUSE: menu_flags = menu_flags::MENU_NOMOUSE;
3056const MENU_TAB: menu_flags = menu_flags::MENU_TAB;
3057const MENU_STAYOPEN: menu_flags = menu_flags::MENU_STAYOPEN;
3058
3059mod menu_;
3060use crate::menu_::{
3061 menu_add_item, menu_add_items, menu_check_cb, menu_create, menu_data, menu_display,
3062 menu_draw_cb, menu_free, menu_free_cb, menu_key_cb, menu_mode_cb, menu_prepare,
3063};
3064
3065const POPUP_CLOSEEXIT: i32 = 0x1;
3066const POPUP_CLOSEEXITZERO: i32 = 0x2;
3067const POPUP_INTERNAL: i32 = 0x4;
3068mod popup;
3069use crate::popup::{popup_display, popup_editor};
3070
3071mod style_;
3072use crate::style_::{style_add, style_apply, style_copy, style_parse, style_set, style_tostring};
3073
3074mod spawn;
3075use crate::spawn::{spawn_pane, spawn_window};
3076
3077mod regsub;
3078use crate::regsub::regsub;
3079
3080mod server_acl;
3085use crate::server_acl::{
3086 server_acl_display, server_acl_get_uid, server_acl_init, server_acl_join,
3087 server_acl_user_allow, server_acl_user_allow_write, server_acl_user_deny,
3088 server_acl_user_deny_write, server_acl_user_find,
3089};
3090
3091mod hyperlinks_;
3092use crate::hyperlinks_::{
3093 hyperlinks, hyperlinks_copy, hyperlinks_free, hyperlinks_get, hyperlinks_init, hyperlinks_put,
3094 hyperlinks_reset,
3095};
3096
3097mod xmalloc;
3098use crate::xmalloc::{
3099 format_nul, xcalloc, xcalloc_, xcalloc1, xmalloc, xmalloc_, xrealloc, xrealloc_, xreallocarray,
3100 xreallocarray_, xrecallocarray, xsnprintf_, xstrdup, xstrdup_, xstrdup__, xstrdup___, xstrndup,
3101};
3102
3103mod tmux_protocol;
3104use crate::tmux_protocol::{
3105 PROTOCOL_VERSION, msg_command, msg_read_cancel, msg_read_data, msg_read_done, msg_read_open,
3106 msg_write_close, msg_write_data, msg_write_open, msg_write_ready, msgtype,
3107};
3108
3109unsafe impl Sync for SyncCharPtr {}
3110#[repr(transparent)]
3111#[derive(Copy, Clone)]
3112struct SyncCharPtr(*const u8);
3113impl SyncCharPtr {
3114 const fn new(value: &'static CStr) -> Self {
3115 Self(value.as_ptr().cast())
3116 }
3117 const fn from_ptr(value: *const u8) -> Self {
3118 Self(value)
3119 }
3120 const fn null() -> Self {
3121 Self(null())
3122 }
3123 const fn as_ptr(&self) -> *const u8 {
3124 self.0
3125 }
3126 const fn is_null(&self) -> bool {
3127 self.0.is_null()
3128 }
3129}
3130
3131unsafe fn _s(ptr: impl ToU8Ptr) -> DisplayCStrPtr {
3132 DisplayCStrPtr(ptr.to_u8_ptr())
3133}
3134trait ToU8Ptr {
3135 fn to_u8_ptr(self) -> *const u8;
3136}
3137impl ToU8Ptr for *mut u8 {
3138 fn to_u8_ptr(self) -> *const u8 {
3139 self.cast()
3140 }
3141}
3142impl ToU8Ptr for *const u8 {
3143 fn to_u8_ptr(self) -> *const u8 {
3144 self
3145 }
3146}
3147impl ToU8Ptr for *mut i8 {
3148 fn to_u8_ptr(self) -> *const u8 {
3149 self.cast()
3150 }
3151}
3152impl ToU8Ptr for *const i8 {
3153 fn to_u8_ptr(self) -> *const u8 {
3154 self.cast()
3155 }
3156}
3157impl ToU8Ptr for SyncCharPtr {
3158 fn to_u8_ptr(self) -> *const u8 {
3159 self.as_ptr()
3160 }
3161}
3162#[repr(transparent)]
3165struct DisplayCStrPtr(*const u8);
3166impl std::fmt::Display for DisplayCStrPtr {
3167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3168 if self.0.is_null() {
3169 return f.write_str("(null)");
3170 }
3171
3172 let len = if let Some(width) = f.precision() {
3175 unsafe { libc::strnlen(self.0, width) }
3176 } else if let Some(width) = f.width() {
3177 unsafe { libc::strnlen(self.0, width) }
3178 } else {
3179 unsafe { libc::strlen(self.0) }
3180 };
3181
3182 let s: &[u8] = unsafe { std::slice::from_raw_parts(self.0, len) };
3183 let s = std::str::from_utf8(s).unwrap_or("%s-invalid-utf8");
3184 f.write_str(s)
3185 }
3186}
3187
3188macro_rules! function_name {
3191 () => {{
3192 fn f() {}
3193 fn type_name_of<T>(_: T) -> &'static str {
3194 std::any::type_name::<T>()
3195 }
3196 let name = type_name_of(f);
3197
3198 match &name[..name.len() - 3].rfind(':') {
3200 Some(pos) => &name[pos + 1..name.len() - 3],
3201 None => &name[..name.len() - 3],
3202 }
3203 }};
3204}
3205pub(crate) use function_name;
3206
3207const fn concat_array<const N: usize, const M: usize, const O: usize, T: Copy>(
3208 a1: [T; N],
3209 a2: [T; M],
3210) -> [T; O] {
3211 let mut out: [MaybeUninit<T>; O] = [MaybeUninit::uninit(); O];
3212
3213 let mut i: usize = 0;
3214 while i < a1.len() {
3215 out[i].write(a1[i]);
3216 i += 1;
3217 }
3218 while i < a1.len() + a2.len() {
3219 out[i].write(a2[i - a1.len()]);
3220 i += 1;
3221 }
3222
3223 assert!(a1.len() + a2.len() == out.len());
3224 assert!(i == out.len());
3225
3226 unsafe { std::mem::transmute_copy(&out) }
3227 }
3230
3231pub(crate) fn i32_to_ordering(value: i32) -> std::cmp::Ordering {
3232 match value {
3233 ..0 => std::cmp::Ordering::Less,
3234 0 => std::cmp::Ordering::Equal,
3235 1.. => std::cmp::Ordering::Greater,
3236 }
3237}
3238
3239pub(crate) unsafe fn cstr_to_str<'a>(ptr: *const u8) -> &'a str {
3240 unsafe {
3241 let len = libc::strlen(ptr);
3242
3243 let bytes = std::slice::from_raw_parts(ptr.cast::<u8>(), len);
3244
3245 std::str::from_utf8(bytes).expect("bad cstr_to_str")
3246 }
3247}
3248
3249macro_rules! c {
3252 ($s:literal) => {{
3253 const S: &str = concat!($s, "\0");
3254 #[allow(clippy::allow_attributes)]
3255 #[allow(unused_unsafe)]
3256 unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(S.as_bytes()) }
3257 .as_ptr()
3258 .cast::<u8>()
3259 }};
3260}
3261pub(crate) use c;
3262
3263macro_rules! enum_try_from {
3264 ($enum_ty:ty, $repr:ty, $last_variant:expr) => {
3265 impl TryFrom<$repr> for $enum_ty {
3266 type Error = ();
3267 fn try_from(value: $repr) -> Result<Self, ()> {
3268 if value <= $last_variant as $repr {
3269 unsafe { Ok(std::mem::transmute::<$repr, Self>(value)) }
3270 } else {
3271 Err(())
3272 }
3273 }
3274 }
3275 };
3276}
3277pub(crate) use enum_try_from;
3278
3279macro_rules! impl_ord {
3280 ($ty:ty as $func:ident) => {
3281 impl Ord for $ty {
3282 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
3283 $func(&self, &other)
3284 }
3285 }
3286 impl PartialEq for $ty {
3287 fn eq(&self, other: &Self) -> bool {
3288 self.cmp(other).is_eq()
3289 }
3290 }
3291 impl Eq for $ty {}
3292 impl PartialOrd for $ty {
3293 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
3294 Some(self.cmp(other))
3295 }
3296 }
3297 };
3298}
3299pub(crate) use impl_ord;
3300
3301macro_rules! const_unwrap_result {
3302 ($e:expr) => {
3303 match $e {
3304 Ok(value) => value,
3305 _ => panic!("const_unwrap_result"),
3306 }
3307 };
3308}
3309pub(crate) use const_unwrap_result;
3310
3311macro_rules! cstring_concat {
3312 ($($e:expr),* $(,)?) => {
3313 const_unwrap_result!(::core::ffi::CStr::from_bytes_with_nul(concat!($($e),*, "\0").as_bytes()))
3314 };
3315}
3316pub(crate) use cstring_concat;