From ec1761f4f3af6bab5c430c619ff62f7ab875b0ba Mon Sep 17 00:00:00 2001 From: Stu Black Date: Wed, 7 Jan 2026 16:13:55 -0500 Subject: [PATCH] Utilities for X11 image capture and acceptance testing. These are put in their own crate so that we can link tests against libwings freely. Once libwings is entirely rewritten in Rust, we should be able to move these tests back into the wings-rs crate. --- .gitignore | 4 +- WINGs/Makefile.am | 2 +- WINGs/wings-rs-tests/Cargo.lock | 1 + WINGs/wings-rs-tests/Cargo.toml | 18 + WINGs/wings-rs-tests/Makefile.am | 40 ++ WINGs/wings-rs-tests/build.rs | 6 + WINGs/wings-rs-tests/src/headless/mod.rs | 133 +++++ ...__headless__xvfb__tests__blank_screen.snap | 7 + ...adless__xvfb__tests__blank_screen.snap.png | Bin 0 -> 2304 bytes ...less__xvfb__tests__snowlamp_in_window.snap | 7 + ...__xvfb__tests__snowlamp_in_window.snap.png | Bin 0 -> 37391 bytes ...s_tests__headless__xvfb__tests__xeyes.snap | 7 + ...sts__headless__xvfb__tests__xeyes.snap.png | Bin 0 -> 6109 bytes ...eadless__xwd__tests__snowlamp_encoded.snap | 7 + ...ess__xwd__tests__snowlamp_encoded.snap.png | Bin 0 -> 37391 bytes .../wings-rs-tests/src/headless/snowlamp.xwd | Bin 0 -> 1232032 bytes WINGs/wings-rs-tests/src/headless/xvfb.rs | 471 ++++++++++++++++++ WINGs/wings-rs-tests/src/headless/xwd.rs | 325 ++++++++++++ WINGs/wings-rs-tests/src/lib.rs | 185 +++++++ WINGs/wings-rs/Cargo.toml | 2 +- WINGs/wings-rs/Makefile.am | 10 +- WINGs/wings-rs/src/screen.rs | 13 +- configure.ac | 6 +- wutil-rs/Cargo.toml | 2 +- wutil-rs/src/handlers.rs | 15 +- 25 files changed, 1244 insertions(+), 17 deletions(-) create mode 100644 WINGs/wings-rs-tests/Cargo.toml create mode 100644 WINGs/wings-rs-tests/Makefile.am create mode 100644 WINGs/wings-rs-tests/build.rs create mode 100644 WINGs/wings-rs-tests/src/headless/mod.rs create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap.png create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__snowlamp_in_window.snap create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__snowlamp_in_window.snap.png create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap.png create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap create mode 100644 WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap.png create mode 100644 WINGs/wings-rs-tests/src/headless/snowlamp.xwd create mode 100644 WINGs/wings-rs-tests/src/headless/xvfb.rs create mode 100644 WINGs/wings-rs-tests/src/headless/xwd.rs create mode 100644 WINGs/wings-rs-tests/src/lib.rs diff --git a/.gitignore b/.gitignore index bf9fb189..e09114e2 100644 --- a/.gitignore +++ b/.gitignore @@ -152,7 +152,9 @@ WPrefs.app/WPrefs.desktop # Rust stuff. /**/target/** -WINGs/wings-rs/src/WINGsP.rs +WINGs/wings-rs-tests/Cargo.lock WINGs/wings-rs/Cargo.lock +WINGs/wings-rs/src/WINGsP.rs wmaker-rs/Cargo.lock +wrlib-rs/src/ffi.rs wutil-rs/Cargo.lock diff --git a/WINGs/Makefile.am b/WINGs/Makefile.am index 22c4b25c..942c619c 100644 --- a/WINGs/Makefile.am +++ b/WINGs/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = -SUBDIRS = WINGs wings-rs . po Documentation Resources +SUBDIRS = WINGs wings-rs wings-rs-tests . po Documentation Resources DIST_SUBDIRS = $(SUBDIRS) Tests Examples Extras libWINGs_la_LDFLAGS = -version-info @WINGS_VERSION@ diff --git a/WINGs/wings-rs-tests/Cargo.lock b/WINGs/wings-rs-tests/Cargo.lock index 0826c6d7..516cfed1 100644 --- a/WINGs/wings-rs-tests/Cargo.lock +++ b/WINGs/wings-rs-tests/Cargo.lock @@ -903,6 +903,7 @@ version = "0.1.0" dependencies = [ "insta", "insta-image", + "libc", "png", "tempdir", "wings-rs", diff --git a/WINGs/wings-rs-tests/Cargo.toml b/WINGs/wings-rs-tests/Cargo.toml new file mode 100644 index 00000000..64cd64e2 --- /dev/null +++ b/WINGs/wings-rs-tests/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "wings-rs-tests" +version = "0.1.0" +edition = "2024" + +[dependencies] +libc = "0.2" +insta = { git = "https://github.com/mitsuhiko/insta.git", branch = "master" } +insta-image = { git = "https://git.sdf.org/trurl/insta-image.git", branch = "main", features = ["png"] } +png = "0.18" +tempdir = "0.3.7" +wings-rs = { path = "../wings-rs" } +wutil-rs = { path = "../../wutil-rs" } +x11 = "2.21.0" + +[profile.dev.package] +insta.opt-level = 3 +similar.opt-level = 3 diff --git a/WINGs/wings-rs-tests/Makefile.am b/WINGs/wings-rs-tests/Makefile.am new file mode 100644 index 00000000..ec5fb970 --- /dev/null +++ b/WINGs/wings-rs-tests/Makefile.am @@ -0,0 +1,40 @@ +AUTOMAKE_OPTIONS = + +RUST_SOURCES = \ + src/lib.rs \ + src/headless/mod.rs \ + src/headless/xvfb.rs \ + src/headless/xwd.rs \ + src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap \ + src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap.png \ + src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__snowlamp_in_window.snap \ + src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__snowlamp_in_window.snap.png \ + src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap \ + src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap.png \ + src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap \ + src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap.png + +RUST_EXTRA = \ + Cargo.lock \ + Cargo.toml + +wutil_c_lib = $(top_builddir)/WINGs/libWUtil.la +wings_c_lib = $(top_builddir)/WINGs/libWINGs.la +wings_rs_lib = $(top_builddir)/WINGs/wings-rs/target/debug/libwings_rs.a +wings_rs_test_lib = target/debug/libwings_rs_tests.rlib + +rustlib: $(RUST_SOURCES) $(RUST_EXTRA) + cargo build + +check-local: rustlib + +clean-local: + $(CARGO) clean + +all: rustlib + +# Tests run with cargo-nextest because it puts each application test in its own +# process, and WINGs currently assumes that it is running in a single-threaded +# environment. +test: rustlib + LD_LIBRARY_PATH=../.libs $(CARGO) nextest run diff --git a/WINGs/wings-rs-tests/build.rs b/WINGs/wings-rs-tests/build.rs new file mode 100644 index 00000000..79eb0cc6 --- /dev/null +++ b/WINGs/wings-rs-tests/build.rs @@ -0,0 +1,6 @@ +fn main() { + println!("cargo:rustc-link-lib=static=X11"); + println!("cargo:rustc-link-lib=static=xcb"); + println!("cargo:rustc-link-lib=static=Xau"); + println!("cargo:rustc-link-lib=static=Xdmcp"); +} diff --git a/WINGs/wings-rs-tests/src/headless/mod.rs b/WINGs/wings-rs-tests/src/headless/mod.rs new file mode 100644 index 00000000..680d15bd --- /dev/null +++ b/WINGs/wings-rs-tests/src/headless/mod.rs @@ -0,0 +1,133 @@ +//! Provides utilites for integration tests that render to a headless X11 server. +//! +//! ## X11 `DISPLAY` value allocation +//! +//! When starting headless X servers, some care needs to be taken in selecting +//! display numbers. An X server needs to have a unique display number and will +//! not start if it is assigned a display number that is already in use. +//! +//! Local X servers usually leave a lockfile in `/tmp`, like `/tmp/.X0-lock` for +//! display 0. Avoiding the use of display numbers that have a corresponding +//! lockfile will get you part of the way towards avoiding collisions, but +//! further coordination is provided by the [`Lock`] and +//! [`DisplayNumberRegistry`] structs. These interfaces provide a mechanism for +//! claiming a display number in a way that coordinates across processes and +//! should be more efficient than simply scanning `/tmp` each time a new display +//! number is needed. + +use std::{ + fs, + io, + path::PathBuf, + sync::atomic::{self, AtomicU16}, +}; + +pub mod xvfb; +pub mod xwd; + +/// Represents a lock on a display number, which is released on drop. +pub struct Lock { + display: u16, + path: PathBuf, +} + +/// Errors that may occur when trying to lock a display number. +pub enum LockError { + Io(io::Error), + Locked, +} + +impl Lock { + pub(crate) fn new(display: u16, path: PathBuf) -> Self { + Lock { + display, + path + } + } + + /// Returns the locked `DISPLAY` value. + pub fn display(&self) -> u16 { + self.display + } +} + +impl Drop for Lock { + fn drop(&mut self) { + // `file` should be unlinked already, but we explicitly try to delete it + // and unwrap the result so that errors aren't dropped silently. + match fs::remove_file(&self.path) { + Ok(_) => (), + Err(e) if e.kind() == io::ErrorKind::NotFound => (), + Err(e) => panic!("could not unlink lock file: {:?}", e), + } + } +} + +// Shared across threads in this process to help keep us from repeatedly asking +// for the same DISPLAY value. +static NEXT_DISPLAY: AtomicU16 = AtomicU16::new(32); + +/// Coordinates on the value of `DISPLAY` to use when creating new X11 servers. +/// +/// Methods on `DisplayNumberRegistry` may be called across threads or in +/// different processes to ensure that X servers are created with unique +/// display numbers. +pub struct DisplayNumberRegistry; + +impl DisplayNumberRegistry { + /// Returns a lock on the first local display number (the `N` in `:N` for + /// the X client `DISPLAY` environment variable) that is not currently in + /// use. + /// + /// If no display numbers are available, returns `None`. + /// + /// To avoid collisions with other processes, attempts are made to sniff out + /// which display numbers are already in use by looking for lock files + /// matching the pattern `/tmp/.X*-lock`. If such a file exists, its + /// display number will not be used. + /// + /// When an available display number is found, an empty lockfile is + /// atomically created (and marking the display number as claimed to other + /// well-behaved processes). When `Xvfb` is run using that display number, + /// it silently overwrites the empty lockfile. + /// + /// Any extant lockfile should be deleted by the `Drop` impl for [`Lock`], + /// although tests that panic may leave stale lockfiles behind. + pub fn next_unused_display() -> io::Result { + loop { + let prev = NEXT_DISPLAY.fetch_add(1, atomic::Ordering::SeqCst); + if prev == u16::MAX { + return Err(io::Error::other("display numbers exhausted; check /tmp/.X{n}-lock")); + } + let next = prev + 1; + let path = PathBuf::from(format!("/tmp/.X{}-lock", next)); + match fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&path) { + Ok(_) => return Ok(Lock::new(next, path)), + Err(e) if e.kind() == io::ErrorKind::AlreadyExists => continue, + Err(e) => return Err(e), + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn find_unused_display() { + assert!(DisplayNumberRegistry::next_unused_display().is_ok()); + + assert_ne!( + DisplayNumberRegistry::next_unused_display() + .unwrap() + .display, + DisplayNumberRegistry::next_unused_display() + .unwrap() + .display + ); + } +} diff --git a/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap new file mode 100644 index 00000000..f8ae3214 --- /dev/null +++ b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap @@ -0,0 +1,7 @@ +--- +source: src/headless/xvfb.rs +assertion_line: 387 +expression: xwd.into_png().unwrap() +extension: png +snapshot_kind: binary +--- diff --git a/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap.png b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__blank_screen.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..0eb2240587df5af5909eb77b209dda5f430d1f74 GIT binary patch literal 2304 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

I6NO8BkU`3v(h`zo>`w>GG;M z7}oo31tJerBJ~j#2pKR@m@- zyo=3!IAw$!&Z}}l&*IlagyviubJ)Ko42h!n>i`>;YZ_^VB9+(i{O|A_ z*Ork=^CdFDTV|vT70x5}BU7GuMas2VMVaT#jc#q5petsmnb$?6Y2yR=?HQ-MP1fW3 z)@u&)K7Sc$OVD@Rdqx~Ou(b8|$BcA3B=D=$Ee3f(x`>Lvsx>uYamQft?R>AStmHzT zpx=P0OoGMMDUO8eq_Lh03Z@^4&U3`my2*u#Sr_uC2vE{pLLd&p=e(LDI@ zSo6EdZC}4U`n}n?p#?nO0vsh*J@1V?$a7g#u{cw(komE?RqrJ=sM6g6U%9_&?kXQv z7eheqM9Om?)1YtlJYgZ}*9wn57@QN)wzzMo`M!T|xg=yq5BY`&rMi47wC4ABE3$+Q zfSxEC-TJC3*N3-jdJy2(0l~zNi=l)tVkZ{bwV57;VZ81*{m5kq6khb{Q|xxuc434j zb=Lm&>ARBY4@$2C?#n_gA)5+>r9u+xyfQ*ZeNFaDLbs?kr|H+%BXdh(vjfz&{d^IF z@hijkszc*SrrFl|iA`Jphs97w31w(^a@9q6$a#vYv%ht#ChNZ$+Pj#DZ0SscA$?aB z=h6_vD#jJ3;hR0jdyVwfd4d)8W8C-rg=DHXC8=p1nE+!~J}pA`JCd20vM1p_>es^P zXxV1NMGgdmZzsRrtmb4S$nyFy9{NhzNU?AJF|{sv2f;NuVLDQdScnOG??E>pxHp|) zEEzd2I5H>go6ET5Dz%sUz+nxNwx{ctz(d7|#4ypM^xx?E$l?Lc9YkOr^qbLG;XC|#0m~S{NRMJaj0G)sj1@84{RfA6{H5^Y) zQ!5Sl%pa-L2L-v;HN)MSz3oXTaaEVDWasA z7I(Za&D*Z8dHZ7U4~u5?3WJ8FXLEnrh8;tN?N@5lEWfqTO_q=d!^7w|Dy`W~h6=W# zd0bB{&8Cbyzj8AKxypj?eq~M zz?32cdbvh#;yI?7%3z$y>I&Q&tM>@Z({UpL&O6*z-P^R{A~$lEw931l4oh$Rr|r6Z z(emPjbS~31+IHPR?Q|PKHkFWWmzugAA8}?2eNe0uJ>qg1uJYeMvK!z$>4%SwM+lw6PyX?7Ifoo;4L2 zfPD$Z`lGc_Mo^tdL54YOuTuQ%QAO2tK7ovjGrrSQtoPPoEpbJSz>}MwKmPg4&1@ZJ zYZJfIf;@2aiyl=waYB8pq3EJjgh<3tV5n4FerIgLx6Bs(SYw8NKPfl&?%CQiG|8(d zEB@G6)M1Ot&crFLO{>*w0({BKd?ZZ^ecm~LOK+VMk{y#f7-KD=b=SdSZfYEZ+u8Sw z@e=mq)|^mh=wj@Nlo>n8jo2V`q{Lz5Cs>G_Q-~g04`8gjq4= ztouyW%!nJD`Ga>}D2`f6IzqCBksY<2Va5aGBUHdTQ%R|JtB`CnUcCuTVZaU|M(H{G3$|-J1^m*|ycK)^$VV4m-%>7oILl z;$BwjYx!cj#IISg7O%;+?17LM#@b~JSL0Gszq58KjL~=g3bda0@lyAU-FKp^+yHgu zD(3*vMmFc)Lr^1d^vaItno~n!gE{DN_J-%$iTf$9x7O0X7S|v5wD7B?mblADiBo4a z(2jrPj1p?I`D1wR$u-2nhmC|qiKgWf0=9fKJM5no5u)(lKua1o=cV29rbMqsaL5U& zdKNRiH}4a=5?*Cz2axe0nYg?akPo5`&p-Ou&9jZ~?k9a(yZb_da6Tqqk}C^hNS2t# zBTiB37LC6;eXwth)Emt_9{R1w)$Y9+izetyabf3!TThO*jkvpRX^FDymZ|x$&S1dP z*vvBs@Wv!NYes-4qxnivl?<+F7xrgSg-LOp)Y5)&Q|+x9X&M@qY+Y|PeioifBSkIH zU~cLc8rqQSSal`^k4pfZ+xx~^(tWR`JBWTR$nu#3A<{yXJiXE=<9}5r)JnnojjrOm z#NVFk0a6O^W)I{Mq#5-7q2JM}WxO(X)8}?32M76tvJ?YMN4`0gTX9MnzBw`bwtR77 zuzGNc4If1%T$v)gep-Nnn5S5hl{QqR5U@b6hq7=Q};e|2e>4=^V6Q zUbR125^CPvG%@|Sk$I0f^05b*M+RE}-D|=yN`*C*9GTj)VqU&P|2w6Qy3G2D^lIGM zYd)gY5vNG>&V1QS%K}yFf5Z8kN5=k_dUd0SXpHs!lZl#gelbg`%;MBP+rC3~*^!#` z4#$MoO@f-{^*6&t7Gj1@IidfuroY^R1x7Y-JPA5-uYi`zRwZQmZOq+mKAUJp|EX>n zj9U{-N$jXk7+2`A=P6(2kKfL7U@7G4``R-IH$0{&r7b|B1>B2_`I!`cOXo_Fs7vNp z-bv*To%pdkc<76k@wBplFM9$#mM+%22lW09rU{(+rk1qH3DalQ!%u*7u-#;<1awLw zcONC-J=c@p8EC^uBPAuZ`WTM|$Di{b>hjfsUFSCjnV6YeQCk;L5}}P7$MLD$1VM- zn5*V#L-&MaTh>d=6}>5$^gdl=H+I05I@Caw3j>E?Scmpzqn*?(BxFI|p%qog{}kR%pD4T!&}pAq7G-7W+-9?R*rUlthCZ zt#m|WWJ_#Y=Y3?i_OJDDX$c42g8ih75OH#HlEr(SU71a^=5=}}vpB8)N=_$*wa}0Q zB7Sfn(S4M9f?#D|{6*JPR%p>^>C0EWCI2fe7 zE-FIs5*LrS5T{2PWiD*b%DX;@J-{A|UbNtbbeLGTk=i`8a?rzskN^^y4_Y-v#!lBpktLsv*T9%+ozZIQ7Vvt!8IOql3Vnn zfWRA>=&RzQ9WTN+ZK;LBP(Q|tFL5Orj7RJ<*C}F{A~<86JE>#}D9b#@v;l1~>Nk#` z6!jz&Jc*PQGTQ&i4@5>vNtSJGF$DGf{M@6YDDODqL-nsWMmM%yT=$R2xKQv%q%JXm zF0>8b$CHcr)mzW7__|jLKq7EkHQDQA>2LFg?j6~<9{v9jUb^d>xRYk?j~tCM#%?f0 zMt6%8m;i%I=^7w{c|lof8#3!JVNzgt!D-rm!c+jmlZMAE#`FfQv+5seheax?StF^J ze^D1Uhi-_dN*r)BZXeY;VmoSAJ~xNQIA(kKUVT-}Jrvs7C9dGZx|QWAEgLQ4)mJzZ z{Ptwl!o*++SBw1(y1~Bj8jwy>^%eFy!&!+F2R$z0RgSu3{8m8p$%}v1C^OTg%!dSS z0-Ul8`jlyUHt(NocAoUCy9+&8x!y&+E=l8mRl?uF91*fD^w;aP{z;H`>%GIP_SS|4 zem+l!q2Ax@M{&?L`+pfNjjKY3E^jTDv# zgv7RjtPr(}BWQmgp?|?lI)B7<9mw0EtAM-imDbd4x6CcYA1;tLoFdZ>nI3%L#k%NV zS>Y;`Z%AbwviF3_xi~U!_4Vb|q#Fmur(Ep&w=?LtJlr1Nh@k6qjH^nxi6&HXD!oMG z2wkE*ORtVIjKQgiNsuW{n>svcLBeZyniL+{_{8=1NnxRKh@cioNjt;87%HLXf)w8j z5go0Symh8xCt-W5>%E0yLw3V{n&dqYtg15p+KPB9v&_+baeTdgJq&;(yF-pfnsHNH z9tR=JtzTOACnP9fTSxWusu@Kt7UEk{RBJ^(ZL!jl=S1=644Ro;VVYRJp`K6!JRWbS z&7B8l&=d}NvhXlj(Ep})+N}H^Jz*L8*M5F}Z<(>Jy(9OZPw|D)LLl<(=EqmP?EX;? zqo=JohRAN8pbsKqOrASlf&ec<>|$x|Zh2LEOcw-3Q$9k3vD6lxA3Mz-h>^%Ka2@Sof)i`U>G=^GQ8?Tpfemb$jH`^hqTDKvCxlD8_8s02I+T2E z@g;0cklLu*Dk8Rf&uUw*XIDAk_$XIG9EG!d((+oG0;NqCoH;bI5i263rN<(-Tb&1 zuxEn!X1>ttAbXa#P-K%<@xMNwEF! zz;A8p=?i1DdC$9UzsBVw?~CB(hg^xpY7!@7Qg{0bWp;fq*o(gE87L7-_Q2pUaLk#- z*xbn)tknxL>b27~G|18_&y4U8q4hB3gkW|RDT)9bBr`V#g7)$akg0SJviFiX)TYp# zYp4-prl}CHqH!~Mg2v$oY;G=BtX{`0Ci48<|n8BimM7Q=h3c$%ydUNqH29jD;3r1c8|mUBwQ1Y&K+kv9<2lz zaXGmVPLQWudwxu46f*b^_5KtPgVz9SpwD3l8fHScshHZWcD2}A&l2NegB!{Ab5n+L zqqgH~ZPs^w+m7(+cIUpuba~w5j27)^iamd*?J|v(k)~o!Nty8&*mu*n1+aY*Q9X%5y7F`7|FfF0K(_TX ziE>mrH@M8{)EVT#H?@WR$k9WlS_)J72syQbem}fjyW5{$6|LLzO1G9LN0CZr3Fj1b z6`{Kv20@gl06T!CVOwRcv739L%&xH` z1hqt&3(09r_{;`PSsO1%B80$w=-VWw`X89+<(|_6)u2NSN&7>f=a!f)8R=_}|4P$I z>n<}!NkaB4cd1RA)dOAA=}k*jT1JlKJ?R0}+b`u+Pv-#WKhU#WSqM*#7s>+?A^t&z zD`^@5{S^~oiLTIhjCsTs%bKb0<|4}U$bXGf4iE?=L z?3%}-Liwh*{?O)6x5zgUHv@Q3@`0N{+=tP{sQq*A?+mR4@fAL=$m-!9 zn#~J%a&I}ldW`d{o6i+k_i4bxTK!f(^?*%^37#kInFlLjJPQa%Q{;*AG*+A6Z$T&) z8HUU@ym9iMcL309Lm1)Rb*z22{6kg?5y_`Gfk#w6uTO4Vcu?Nyg3g)EtgvC-dk!Ga=p54?H zkZFUEnV{T~#g@Q7O930XexX~*AJ_yrHIwA^OD^P0bwvNd)Lbz%DZAB|1ysigAyI&&* z-8(yJV}%v}HLrLWajF?g_pBCA{KIU4jAGG>7gL4oQ1aFIL$|w43M^rPALiLsY1Iee z?XD*g)lCJ8cstjZ4dN zpT6!}x~U&mW|o7Q6O>P=O1C_N0&;_{tr7QIA57J{IpW}?J{?!(y;*zd`h*>7y(Siq zz}8t`1xkVc|&qXDH)p&lN>3_d$$q) z1CzcCIu^{-zM*V>!_}H;v7&%ZLH><##Xkw}J`8HlO;|M=%ZHkOh}Qis!c%tm{ZUAm z{L)*;Vvrm8z~dsVQc^t;BOp?D&SmSy`Um=u5jQWJKb*Y=H}5|w$j_f$4R*w1)js70D5GbS^k{u3Q>v_vytlz# zN@W~Y{TY%`?#I3w^^;P^s6E0oaiU8>`)N?KJBIJS*qP&DK^CRJ6Mo=z{VV;`nO>M> zQs>5PhJIWXa|;rUmYS}J@^&Hq?GnO@$bDoBnERAj$*_$Al1-Iq!YOO;;|x2{Z)gyJB*bCFdD8K~&8?=La- zoEJG0WOCdQ{1s)J87cU-=a1j>PCE5};>`Q^KsZXE6K;3|M%=9?J=9)85|I~J^x%dN z>YTWn1w4VY1@aV+GMi+@4tt`?)O0IC%`w^uI~)vBe_WhdP`Q zVP^BuC=CUUn4DYTi(hRHJ=PJoYrF+<5!y%C+t_N=JdB{> zFq03O_MgXX(&J81h44RTDqKLol($Yzz;S~^%-$;=Xp93v}*f6!rZhC40;SDN?@icoiOX`mvt$GqpC2WR#Am-RB)+e5_6{D zW>)J?^+3zDz~60oE4oFar+aHNhK=8GvWkHRb0h7aJ`u`G1($XYXIjQ&&_6A0E zle@5!J?79~Pl&*w)>tL;swp;kFk`tO=(QOkawyXu(OArpf*z!;oNd~| zihI9&4frfbePSf`kh<|W-@=gU55m(k@XS^r;61A4&7XD_kJM%qg0rKwJ-97Zn1cBk zZjXy|Uu^H`&SaLp&UIdKYb~l7ITDO|AcqA|RLwcuY8vQzr=tS1xoBjbg`T94khn^@ zC6H)8zT94*GcJB9?a3i@o@asDOZ- zT8Dtse47zR-2PGs)3?7r>Y@-fC>{`cyundb^YFFBWPgHn?V!6VA+L3RmA=7`_FA|d zrDt024^i#h1g@T(Wy2Ci!AH{j9O7256cm3P$Vk+>272P%ES>>Kj|=A;pYtu$)tR=v zMNR6MB;qQRZp+yTN_{aD!j28K1FHlnCH<~?C(!oX{GE~Ik+pZR;*`@XNk^+WVZ!qM zZWI?q3Np^R{rlWCRZ`-{>h`sY@@&D;?<_fBK8STe>)FC1LPSdFTr_aCiaTYIXfZcT z%?XE|KJq^IyV-9^z&8;KvVsUJ_s$_~KwT-u1-#vZ)^*74U0*#1A4?17kR&q$xOv%U zcDZK~g)^71-xQnJ8J1x2?rE3~Vsyf{#Mfi^y11PP)oL2o(+dJ!HZMBKH5hDb1X#B@ z?<>cU{%?et&HG8R)h<_W{r-@`W760(v@c zG9oddDDS%S?nT*!12NX7f)Xq#*ZJn6M+_0y$iz<+1LDvzUE)n=D zspq$MMge>;vk0D2^$lqN_VjZE0MfzMMg_0obaK@ZaZAG-Wf4id^7kyYnjpiHJqMWv z)cOF!pfRb)E*qzH`PHlhr0~!@*LAJy8Vw9nz-I*9LV`p+q1xu}v{zK2$He5zS41gA z!mICUs;9+J&gP+tH4SFsI~LwpWl^a+X}H79pJ!{o#iPZ(Dj)h}KcVvSuKuuQ*L-rb z-QM(aAHu9S-^_wlXGycez@La;fhh078UykgIcAZ3(QmapQdx70rz0_J>`4P9sm=b6mWG#ON?&f2sHJ^%h%AAK38r zglEqhgq+eYFy_r?VHf1u71-LgVe{t)@%rfdRTCs@Lmnq~{nc zACmoI$*Xl9)VSFMe=vlxP-^pv0|nJF8OGtmPrGgPGcevR=XZCkOVw{LP-dVM28`Ih z3D-0NkAodk{r>~tO{MnVaZ7D@+au=!07$fviL$Gqa}$czAALhWC0WvtHCAB*7lwBo z{1HbnR(1Kn-k0^B>L!(GH+wa_K5`^qvv@|&r-CmEnYJN6LbaZ%<{Fn&?k?P`Yjg-r z{Nwf7hPa4q7$ZZWlcoMxgiPE^Y$gOElc{8Pm<2@2>X!Kq9@vSp@foplT^$bK?co!) zRydnKK65bG>0~iDkzIHa{~Xd}&rOW5h<&JL;@@0jL&$~xX*)PD*q;-LZw{INH#Ik+ z7FEjnB~&uQN{Q4#3_`o_HpJh+_gHnT@JGImLLJ~O2!X?vR6yd%8c~G{;@mQJNQrC~-v2!A@;neVc3jLqq+oVOjTK{<6&Kjw|}w&k`_)Cm*GO z+`Z*U&mo+vWjYhhPd{Y|s29Z_kZv z71Ztc40bpnQUX7c+*U34rE^<57g!Ukh6JP4YRhy9dFW_<32CO7n%`(3aBvlhi!-Rl zrTllV#G3gLeXL?Fycc177gzlkE|jd7DwH@5MOZmFGybA3nZyyVNidf*L15d|ti)1M`bydrCk0)x`g?A@@4E7xeT>w|Gt zAqPrmbTH^>Co;r)=#iGKqZr^Hd^;|FgjcyH!o{?LQh1D~!*L?ZP}l^c+h~TLqC?z| z8@+VmkFEh-74Jo-OD|GCb{g@iQ4yuYMr(c-<_xp^d}*KZXt%RDT`iZLLpn(aQF-+1 zZHX~tt{dq7y4ikjkGiktp=|8wnUKgwChP02PYmux%Oo2l`-f!6OCX}a6cFpT{hOI? zbM%Q1gq*MOru25+q?ek>_<5%M?25&@EQsqGfs%-y^MnzE3(s8>{txo;^5R^A^dXCN ziQ$1Csuw?7i4QJo4z=F(_4i2UE=mlq9^zG@Yrif?Q_`nQ#jjiFo7vV7zA~Dl6bSCz zhgBKHdJi70y`U8~vU_BCvnNpnE@u-ksy7k>3C6Z16f>21065moJkZA^AqcU~#<30g zIpI#c9>WW9rz!bRW1?1zv9k-E-j}>jC(>eh4HZiYVb9a~v}cS~C1iUZ1xDb$7)U;k zwFOA`Ox=<&fbJR<)}6UJQ2JjaLj1)t3#8<0vqwZ^rDDUgUhcovjI}`p!+g}I)&>#! z?OR>g0eu4l1^b8{YdZamKw98+h2F%koMg@*x||~?0dV=9e_)P414HG^(y&}!17$EY zVf_tISY{rzfrA+Ym)1is{%Xb+qM>U5wF~KolS`d<2^}$^!-u4q%F3%l>FBtKHQF*} z75DtlF0HB&1rHRU9J{enpx9QHV1af}MfRvkChodjA(p*4K;WW?JNK?|G7PxA<(=w> zkgMeyLtc7won`!~1iqG9YgkpnWi8w;|3J`@z4n7rtEQmYb4>|NkLkSCsG4xD87i}4 zf1pRhhdZovS83&Hu05?X@+iCu`$x^KjF6UHp}CI{1c|UErB85NQBa(PtDV(J%#W9d zH9W7o8^CnWf92vcoKys^z|+F%>mHMIGTQ)ql|} z#f7UE`$Ky=vv~6Hm<4&cC%-+_7`VRu<+IPWyR8Wm(Hrn8aO{tE%4&6>JzE4zh}0*R z^09)@1eUNT0@;%xn$_Gr{L-ZDFHs+hVxP`Fur64b`%|8U?%>->|Hc(#;kYx>%AIJf zCGUVdy~whZKS6IF-s1Jggr~wT6E%xKZMGQR`0V%EB&)u})(55wpDl+@z~8cdeXRF9 zF`9(=YOPArzwes(sKCw?y-u3b%aWLN@n~^p9y6KJQ3c%&cJ`uOA-z`m*`duL7l@$a zKBo1NUBSK94cM7})c+!ZkDV_o^Z}UkLe|}j2yTnb(M= zd@lH9`7fFl?B)@{2D}PGZLn@QYoGzuZ#cDBzsTEj^=HSo^OP9k_m5a2(4m??C$){n zqDCvT3g8P-OTCwYW%Ni(#r3eJ!>x8-LR;%WlE>^HCyyDhG9Bw1_Ex{A3sQF)W8b5! zkbF%vQVMw{-yD*@+F4##iyK3&UtdMtkL$hvA+zu!Q=898k1DRe@W^|{4vQQdE)vVLV%nRO{Y%reW_nBsa3f=9KDoTm$$I|ULeLciNc zY>=dG-(_CuG4_~`4N(`@&0J_N6|T`&36s+18h?&X*{KY@3T`!?!o=q0AMT zmu1rD>{R;a@^Jx-gIx}sTv~o02|dbt>?^aUO_ZkK#viJ`OX$^IgU`AR-q8J($lh@E z{_XxeBmmt)EZj_ewn^rTIh-zuY(uBTGuF*eC2AqbeOmvO)Z$boRhP;)Et9OEd17Ho!k)Z z23bb8I>1ZlVAHy;9;5W8KCS{-v2M(u!gJlU|zO^y1@Z^!~a_l*iXr{U;;e z_VfQ7PMJ))QM2J}uyhmPH_bfb>kmfZe?n;;3aa|4>w^AwC{q1vW+PhNW`T+u&by00 z&`Ry(AHRmsJhu;?E?g(K7Y)U%q*S~@Aac*_c2l&e*zgN(Xf}4QLF!v3pF0)iwN!b7 zP9=M4Jf}S_{Yd5g5Zt61`6e!(FW_ggK2xR70o+fnT8(>-%YO_bM=m7i|250n%`2|H zDSF8TdjB-&S1}uuy4S{XEpu#T>PBq$;x8Sqvj%6gJ66WS;RqSiX(jj(80uPgL{Ia0 z%e-MeCQ)Z+8t#wq=q}d0-Z&&IJiHRotT2zbYI(V?yx>9jKIC-#&kp@s3{CM)LW#0-bd39luFr3!Xg@veI9I}Ey8XO8m) z?LL32IkX7LfV=@cknVjJ6*rS1fM>&spS0C+UmW8LBgHS3^*uqMd973L`sCUQ`cK?< ztpTB%4x_Hk`YubmBK;b##(Cz^k^EXrUizE4xplZ8Nb&mLElz9mm{-NDVN$ zoGqiXkleE!@+9&s@_ClAt1678Vo{a1^-dG$)pYehv^5Q|RXpJkWBYK~c4%kE?s|8p zWVANRyman!H)YmIgCVN z4VFVCJAJ1MYlRFYuigL8l<8Ky5M*BeebaKK?+t)}Yg$$s>N0>5dl;X!M$D#T)dKYk z21~~22c*%mK^MC}=Cf3wqUFq#%;?8j%dmFGy7>3oZgUa~Eh;^X4bBzpGEWLFe&Ji^ ztE`k@YG;>`0^X&lERd84MJV2`uvQ}E%mrt}clMsAFp;>-_50ndMT|N#BKTx_^b4C_lf9W8i*jS=tN`bShSi;P z1x4^`uQ=w;Zn#V@R<>XTal<^LC0Sv3tH-z;@-&LkmE0jO(1LU6YkQs1ERzu+CDIj^ zk{2P!u-P!+xPC{jr?TCBfpLZ5R!irvxI$z;A!Y8+|Gz9@nFuL`JPSRPj^v<-sVmCT zt-);-Sr)KEuwUY&&k`VX@^#4vT1QqGt~xq9eMs8_0{`4rad+6h!gIXw`U<7`TwtuW z{)VF=hcytuRs)ukC;leKiSpmKwj=3ZKsebLZE*qms&$V zQ73(ZXM5isuWQLr9q5-~^CJYXKGcQpF{IS*OKwX8-)CrD*}_>V?Q$OtHJ!#vKj=zd zx&6{rV6*2o{=q%h^3s?j3pvo6FBaA4%SY&E=x!Nw#_C5KBc8Uw7w!>FYHD$6$B&QA zshtV8yD=M-F=T9hka?rvWF8=Qnpzr~i!~n6m3Q)hrf7=(+X|c_of_HH5>f!leM{i= zjm4|bK5I?=#};0aGSP;12+Fa}x0jHwWE#a8t&{aJjP^oxS;^TW z7nSno$tXUu9%0z2ZO>i6vgKaKdE9n=nOZ3$e=MVGS0?MR<#7=1*JArv$WFt_;uTq$0h99j;!k){)ah+B=}$cCTc(m1RZSd^aI} z{_ApBz2;C)xALx%i)4JmD>J+>!h_kDgg?Tlk#Q@j;5pl&#LVvF zWkFTCU1?H4(haST;3K-a3)$ueLcu9_1jPVW)TNe3^|YPNFKHZUZaQo^@M#NvUF zEvJQaCF`T_03bG4yUp**?lZCG0Ypq7|nh9SeD;CBsp}bw=2IZ5B5+V%NQLT z4*~#=wjx^po5j&cD&1Cc^Pg;UM)ewnW1Z#pY&d6 zRgL_+Fb|K-F2Gqt^@2(r`Mmwi2{$O_VV*SH@#7vaTIFT@Yo5+OY=fd^O>#?h9&Mz| z*7Hr#X#{M#IvGNj1=|Mg`nxT<3*(5mLAnops>q!vmEhxnQXp=WSLFwz9|Ztbi`n0Q z$ApZ4;7={7j6DpOa4xS9L;c2{*#)?x7Q$w(Y-6?=a;Otw8aU@gk(yV0oI5?Gy`$_V z*7?JCkAfp4OiEtx>VNAPQq%7K`LV&+ealc6^CfOs+}K@nMj3OPNEqyZ7Wlib#4-!e z)mfdvcNn!Af9M)@vKknbS#kLWSsgbXxBwKlBO*>;TNm~=$#OUUWa=?@FV%}yC8J}Y zzuE%U9ubHsA$?wQ%3DWI89pLd&V|XVcuY(i;VwZ8dIqT&T1mg}s(Y{9{@XKam@!Ob z@#*mzX^Ag%f*tiyDYY0|Rr~&nL!ONAC$V_R443Ixc$meOAX|c=mxOalGr_YE#_Ntq zW>ABYH6<7?2fm67<)7rh%{gZMJZg9D>jQz=)Ti~;p}qQhHkUgBkzN4rfi3m`J^&=- z*~@C7AR3qgUCyZCOPkZyourEUP2?jI>hF?*9-DuXue^!9PxI((oSCt9yH!E+%>9+FPQwz_jmSQl z?)%35QMQFDL0~o|Qp<$4U;Dhjy7|i)gryBc))Oy}6lMISEsL@5OgTyOC@`N)%>H0`5Cbz|nw)~3#*Nh?$BD&ZKtS5zdISuiqc*%9Q}NGnZY<+RKFV5Ok?0~?Hg;D5n8-+L!o zbNMl@W%xYF6g$HO$IjAAC~pat_kU$~p9de{oeIxBhOD^Y7djJE6*Iixf2v;aR5^O_ zU+$G?k=9*umj0*`G1IoHhCN4Nn307{pGMefGIRf7=k9!W)u|+*Wf~cv)ZiyRz0l?v3ac>)In=XuSAku& zc^0R5tcog}ykbMTCRg^!hyEaHC6guPR+M>bf^gy~hwDbHv0HtmWiU`-820)%ee$?3 z9O&IC+anp5@Zc1>*%Kny6GSB#?c2|CEf)Q(5LE(V0Fdt<}Eyn z3e?{~q5{hVDkyplPJvi=@$%)*EcTb-cE&*tID?=Aced+D^@ zcIOH#u)ASA#k34;m+3qWL;9oYe~omV6sS$fn7;5PlP0tmq6OcBYV}vgQc~R}O_(M8 zs~jh-^7JN;0K{-(c{At7U*5`kzsOU)_NHp`3$QF&?pC#(oUx^8v$VI}a}(#9FF}fH zW5}(|`XO9ba{+ALqt&f$CoLUrU01)LJ>{fIFov9N{|4GLx{^1G3u`aYn@l{b#$djh zLVzGx!9wbgx|`EHNA~*{-u{ZO3eHJZy?Hl)phFr+xWWe7pdcU+;J#}6aP>fdjyB?| zUWdH?EGA~_`t+E#fbi#`G}IP?c?P@I5fzvPv>Wll6$YPs<95rd$Debbd&0jN+!*8A z!_Kx7X87ReYFGYNdP!{LUL?6bYgQ=ho|jatq0qW~N}5FYN1<2L?v}4mPgdYxvg;JD z7s4h++S`5lFXITa6TQoCS*vws8{!1NeLp^#nqq;@oQHKdWkjQ5gF4T|TgCIr5ZQ0x zdh%Zoq4Zd_l%0QsKRmqfY$Nfq z_*nG8duWm!Z*yqWpeSx^^-Pyy?%lGpTAkUJS=aL1E0P&%L~)d?g&X~{iZ=_kK0Tma zOsm!w4YUB@hMSjqKcNhuhc{*O^)cs3T)~XV^koMr?2l=jp3z#FWsD4e;FC zc((OXb*ie?hZbM1ChmXls&^^%T-j6?nOeAWV+?jbPTl_pVsu2CTes!3WdL+X(CM3> z9leB`yJ@Nm;O;DV6~tn%`P!t!%PsW~<424hpTW0w);w(}8>Sqf*($FR zckafp7O`G}?2_!F-#@=PADR-Q-75{&AHRg)3fv1%Nj5+a)^p)bs-fMRbva3wP`Qzr zF+vLY)L@P<{omKgScQ^N(4&nfmQw#HjEU&;7fdC5Fa}QW|9%UI5|=66sJraF+f>Qh zf+f~v6J=4T=oD?9+3*?ZS|9k>3*KIoRmHI770~LVdr$aDCWhDbOXeN1lIO_7vhd>E zoh6oczFs5{JzdWY-Odr8{q$eEiB+~%F&yO|?aUc6*`_k=)9bdk{97*b$)RKdCaiF4 zQHgnW4gZ;sa5aAY&)es$3*K;y?SfPF;tixXXa6G)d73RpuS}TS$Va95yVLs%0$nUe ztKYLJAiLP8Pj9)4Wnu@iedjK&PFIT*GK5Id&`xLdX6vm~2?ddte}k6Se-E7%tE=^_ z2fgmDY7QFri z`Xz+a0bl6GXU4|NV#X?qxZ|bW3$))$Q`zN2-v%=xeYTIu~l554VL=q>9ovV(14dh-eWz$lRq6L)=RrKL|bI9?8~a{BgtUKE+y zl+vn=TS+fa@@_w;=WFn9-A^R$wUYue%!$G=#cj_QZ&{ul@n_>>tdzKIR#lPkX}wGr zxHEq*mS&7`tX@1?^@1FL-Oo#+Z*U*?&GPJPZPPAuacQc8g)(i-Q@E^wN5Pm22oJZK zTxNnNnPsn~|GALG9$z2CT`>fLAqgq*GP-#@v>jcREJyb`Rn4XyNuvPPRWz5Tbf;EaXI!MX!evzO(l-zm#(+dh#|;-kUV zqi5WAv`0=VDHW>Wh}`z2)bHr@qftAzOjzQ%B~gA+>*|h*IepV(-tYT+A+GAB*!}jW z1^++ZXce8aw{v<(h0`iMH|0%+^)VW zGHvfuk%G|2&%ODkUU|94Dzi$QPhs7QgL{8}d-1RK_Wk?YFP#UT743cP^RBJo)taBG z{+&F&|3m8T$B*7u?|WaJ8}#L`DgWDNAMMoVz5dxcRp3SH{cAJL8bPa!a+kFHcp)nn z%YGsQE+flq;4z^S;sdpK54Jj_9+|dd z$;O8}Hn6fg7}>u&6uVD!{{55PGmaNLJh~}gOfTZij$Wa+Y0*pL?AI7}8W|=hY!j3Z zzCN)$eEETw%Z0gTZ+JGhc}CqK&qq4`g0+=7e?BCavNP|leSc=(udn8BneYE>@?FL) zK1t%1M#Y>;|7LBAS zZ?(Pi3X3e_(SFAD$S!GP&M0X{@{7EOQ%~#Ny9*qC*9C;U~w`+!p*NC=8IEv?OFHPR<+oZ#rx#rKr{7AiZK`Pwp zm9Hy!n`iCqkzRfCQ^B4MtJYlpT&}Mvcm1E;=bv}NZi~jccWl1HD&T!cWBxD8r&le$)(5XJzQ5Ve@v8sY_1XJsx(a?=@_Y2;%hj{TwX#mhzB$vH{4(iX{QukcxAX6L z?z(F_w|Ird!*!Mh$$Cq;tR}_o|CYCZORM$N)v7KT?^JL0?S20?rH`44aOhSzI~#+t-WlnYM1f=iI4f5A~G8c0Bx~aD<=#d*!Rin`g?# z+HT4VyZHC?>3MtqJ*(aQW}U*ilzlTclnbgQz58x0{r09bzuZmHdiyW>(>mTmE)e^{ ztuhJNfCP@6&o`dM1ZHJO3W07q0iK5I%mlt@b5SbfbX=z`JmB38P94(}!5vMZsvRV6>$K>hF!V f9*0<~;MjkD=hmD6`40;53_#%N>gTe~DWM4fDYgO8 literal 0 HcmV?d00001 diff --git a/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap new file mode 100644 index 00000000..38d8d74a --- /dev/null +++ b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap @@ -0,0 +1,7 @@ +--- +source: src/headless/xvfb.rs +assertion_line: 402 +expression: compressed +extension: png +snapshot_kind: binary +--- diff --git a/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap.png b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xvfb__tests__xeyes.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..a871d5b7e6f26ba4c6fe085340a70eb903ce794d GIT binary patch literal 6109 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 KFUl|H|N3v4B+xzp literal 0 HcmV?d00001 diff --git a/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap new file mode 100644 index 00000000..5bf63630 --- /dev/null +++ b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap @@ -0,0 +1,7 @@ +--- +source: src/headless/xwd.rs +assertion_line: 321 +expression: snowlamp_xwd.into_png().unwrap() +extension: png +snapshot_kind: binary +--- diff --git a/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap.png b/WINGs/wings-rs-tests/src/headless/snapshots/wings_rs_tests__headless__xwd__tests__snowlamp_encoded.snap.png new file mode 100644 index 0000000000000000000000000000000000000000..6d3be375dcfdfe575dab4dd96d2872db5a039fe4 GIT binary patch literal 37391 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

I6NO8BkU`3v(h`zo>`w>GG;M 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 literal 0 HcmV?d00001 diff --git a/WINGs/wings-rs-tests/src/headless/snowlamp.xwd b/WINGs/wings-rs-tests/src/headless/snowlamp.xwd new file mode 100644 index 0000000000000000000000000000000000000000..fe1e1c068432f3d5517189c29cb945d2f8a613c0 GIT binary patch literal 1232032 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 z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK ffB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFz|r@1!51V literal 0 HcmV?d00001 diff --git a/WINGs/wings-rs-tests/src/headless/xvfb.rs b/WINGs/wings-rs-tests/src/headless/xvfb.rs new file mode 100644 index 00000000..ab10bf02 --- /dev/null +++ b/WINGs/wings-rs-tests/src/headless/xvfb.rs @@ -0,0 +1,471 @@ +//! Provides utilities for headlessly running and taking screenshots of X11 +//! programs in unit and integration tests. +//! +//! This uses [Xvfb](https://x.org/releases/X11R7.7/doc/man/man1/Xvfb.1.xhtml). +//! +//! Tests of this module invoke `xeyes` and `xwud` subprocesses. For all tests +//! to pass, you may need to install these X11 utilities and make them available +//! on your `PATH`. + +use std::{ + ffi::CString, + fs, io, + process::{Child, Command, ExitStatus, Stdio}, + thread, + time::{Duration, Instant}, +}; +use tempdir::TempDir; + +use super::xwd; +use super::Lock; + +/// Arguments for `Xvfb`. Use `XvfbArgs::default()` for default values. +#[derive(Clone, Copy, Debug)] +pub struct XvfbArgs { + /// Width of the X11 screen. + pub width: u32, + /// Height of the X11 screen. + pub height: u32, + /// Bit depth of the X11 screen. + /// + /// This should probably be one of 8, 16, or 24. (And if you don't choose 24 + /// bits, you should have a good reason why.) + pub depth: u8, +} + +impl Default for XvfbArgs { + fn default() -> Self { + XvfbArgs { + width: 640, + height: 480, + depth: 24, + } + } +} + +/// A captive `Xvfb` process, with affordances for running subprocesses that +/// connect to it and taking screenshots. +/// +/// When dropped, child processes will be killed automatically. +pub struct XvfbProcess { + lock: Lock, + framebuffer_directory: TempDir, + process: Child, + subprocesses: Vec<(Child, SubprocessMonitor)>, + is_shutdown: bool, +} + +impl XvfbProcess { + /// Attempts to start `Xvfb` with default options. + /// + /// Returns `None` if an error occurs while starting the `Xvfb` process. + pub fn start_default(lock: Lock) -> SubprocessResult { + XvfbProcess::start(lock, XvfbArgs::default()) + } + + /// Starts an `Xvfb` process with options specified by `args`. + /// + /// Returns `None` if an error occurs while starting the `Xvfb` process. + /// + /// This function connects to the `Xvfb` server briefly to try to ensure + /// that Xvfb is ready for clients to connect to it. + pub fn start(lock: Lock, args: XvfbArgs) -> SubprocessResult { + let framebuffer_directory = TempDir::new("wings_rs_xvfb").map_err(|e| { + SubprocessError::new("Xvfb temp dir".into(), SubprocessErrorType::Spawn(e)) + })?; + + #[cfg(target_os = "linux")] + unsafe { + // Kill children if this parent process dies catastrophically (e.g., + // a test raises SIGABRT). + libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGKILL); + } + let process = Command::new("Xvfb") + .arg(format!(":{}", lock.display)) + .arg("-screen") + .arg("0") + .arg(format!("{}x{}x{}", args.width, args.height, args.depth)) + .arg("-fbdir") + .arg(format!("{}", framebuffer_directory.path().display())) + .stderr(Stdio::piped()) + .spawn() + .map_err(|e| SubprocessError::new("Xvfb".into(), SubprocessErrorType::Spawn(e)))?; + + let process = XvfbProcess { + lock, + framebuffer_directory, + process, + subprocesses: Vec::new(), + is_shutdown: false, + }; + + let now = Instant::now(); + let display_name = CString::new( + format!(":{}", process.lock.display) + ).expect("could not construct display name"); + while now.elapsed() < Duration::from_secs(1) { + unsafe { + let display = x11::xlib::XOpenDisplay(display_name.as_ptr()); + if !display.is_null() { + x11::xlib::XCloseDisplay(display); + break; + } + } + thread::sleep(Duration::from_millis(10)); + } + return Ok(process); + } + + /// Returns the number in the `DISPLAY` environment variable to connect to + /// this X11 server. + pub fn display(&self) -> u16 { + self.lock.display + } + + /// Provides access to the `Xvfb` child process wrapped by `self`. + pub fn process(&mut self) -> &mut Child { + &mut self.process + } + + /// Attempts to clean up all child processes. Returns any errors encountered, or `Ok` if none. + /// + /// Child processes are cleaned up with the following escalating steps: + /// + /// * Call [`SubprocessMonitor::on_xvfb_shutdown`] on each child's monitor. + /// * Kill each of them directly (with [`Child::kill`]). + /// * Kill the `Xvfb` process (which may cause any children still connected to that display server to exit). + pub fn shutdown(&mut self) -> Result<(), Vec> { + if self.is_shutdown { + return Ok(()); + } + self.is_shutdown = true; + let mut errors = Vec::new(); + for (child, monitor) in self.subprocesses.iter_mut() { + if let Err(e) = monitor.on_xvfb_shutdown(child) { + errors.push(e); + } + match child.try_wait() { + Ok(Some(status)) => { + if let Err(e) = monitor.check_subprocess_exit(status) { + errors.push(e); + } + } + Ok(None) => { + if let Err(e) = child.kill() { + errors.push(SubprocessError::new( + monitor.name.clone(), + SubprocessErrorType::Kill(e), + )); + } + } + Err(e) => errors.push(SubprocessError::new( + monitor.name.clone(), + SubprocessErrorType::Status(e), + )), + } + } + if let Err(e) = self.process.kill() { + errors.push(SubprocessError::new( + "Xvfb".into(), + SubprocessErrorType::Kill(e), + )); + } + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + + /// Runs a simple command in this display server. No command line parsing is + /// done, so `run("ls -la")` will probably not do what you expect (because + /// there is no binary on your `PATH` called `ls -la`). Use [`XvfbProcess::run_args`] + /// to provide arguments to `command`. + pub fn run(&mut self, command: impl Into) -> Result<(), SubprocessError> { + let name = command.into(); + self.run_args(name.clone(), &name, |_c| {}) + } + + /// Runs a command that you can provide arguments to in this display + /// server. + /// + /// The `f` parameter can be used to modify the `Command` before it is + /// run (e.g., by adding arguments). For example: + /// + /// ``` + /// # use wings_rs_tests::headless::DisplayNumberRegistry; + /// # use wings_rs_tests::headless::xvfb::XvfbProcess; + /// # fn main() { + /// # let mut xvfb = XvfbProcess::start_default(DisplayNumberRegistry::next_unused_display().unwrap()).unwrap(); + /// xvfb.run_args( + /// "demo of xeyes, angel-style", + /// "/usr/bin/xeyes", + /// |cmd| { cmd.arg("-biblicallyAccurate"); }, + /// ).unwrap(); + /// # } + /// ``` + pub fn run_args( + &mut self, + name: impl Into, + command: impl AsRef, + f: impl FnOnce(&mut Command), + ) -> Result<(), SubprocessError> { + let mut command = Command::new(command); + command.env("DISPLAY", format!(":{}", self.lock.display)); + f(&mut command); + let mut monitor = SubprocessMonitor::new(name.into(), command); + monitor.with_subprocess_exit(SubprocessMonitor::require_clean_exit()); + let child = monitor.start()?; + self.subprocesses.push((child, monitor)); + Ok(()) + } + + /// Checks all subprocesses started with the [`XvfbProcess::run`] family of + /// methods and returns errors for any that have an error status, or `Ok` if + /// none do. + pub fn check(&mut self) -> Result<(), Vec> { + let errors: Vec<_> = self + .subprocesses + .iter_mut() + .filter_map(|(child, monitor)| match child.try_wait() { + Ok(Some(status)) => monitor.check_subprocess_exit(status).err(), + _ => None, + }) + .collect(); + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + + /// Returns a screenshot of the current framebuffer contents in `xwd(1)` + /// format. + /// + /// For the same in a more generally useful format, try [`XvfbProcess::png_screenshot`]. + pub fn xwd_screenshot(&self) -> io::Result { + let path = self.framebuffer_directory.path().join("Xvfb_screen0"); + Ok(xwd::XwdImage::read(&mut fs::read(path)?.into_iter())) + } + + /// Returns a screenshot of the current framebuffer contents in PNG format. + /// + /// Panics on errors. + pub fn png_screenshot(&self) -> Vec { + self.xwd_screenshot().unwrap().into_png().unwrap() + } +} + +impl Drop for XvfbProcess { + fn drop(&mut self) { + self.shutdown().unwrap(); + } +} + +pub type SubprocessResult = Result; + +/// Errors that may occur when a subprocess fails to run or exit cleanly. +#[derive(Debug)] +pub struct SubprocessError { + /// Meaningful name that can be used to determine what subprocess failed. + pub name: String, + pub err: SubprocessErrorType, +} + +impl SubprocessError { + pub fn new(name: String, err: SubprocessErrorType) -> Self { + SubprocessError { name, err } + } +} + +/// Error details for `SubprocessError`. +#[derive(Debug)] +pub enum SubprocessErrorType { + /// Subprocess exited with bad exit code. + BadExit(ExitStatus), + /// Could not spawn child process (with `io::Error` as the reason). + Spawn(io::Error), + /// Could not kill child process (with `io::Error` as the reason). + Kill(io::Error), + /// Could not query child process for exit status (with `io::Error` as the reason). + Status(io::Error), +} + +/// Manages spawning a subprocess, monitoring it during execution, and killing it when `Xvfb` shuts down. +pub struct SubprocessMonitor { + name: String, + command: Command, + check_subprocess_exit: Option SubprocessResult<()>>>, + on_xvfb_shutdown: Option SubprocessResult<()>>>, +} + +impl SubprocessMonitor { + /// Creates a new monitor but does not start any subprocess yet. + /// + /// This monitor may be configured further by calling mutators like + /// [`SubprocessMonitor::with_subprocess_exit`]. Once configuration is + /// completely, start the subprocess with [`SubprocessMonitor::start`]. + pub fn new(name: impl Into, command: Command) -> Self { + SubprocessMonitor { + name: name.into(), + command, + check_subprocess_exit: None, + on_xvfb_shutdown: None, + } + } + + /// Sets the callback to execute when [`SubprocessMonitor::check_subprocess_exit`] is called. + pub fn with_subprocess_exit( + &mut self, + f: Box SubprocessResult<()>>, + ) -> &mut Self { + self.check_subprocess_exit = Some(f); + self + } + + /// Sets the callback to execute when + /// [`SubprocessMonitor::on_xvfb_shutdown`] is called. It may check process + /// status, clean up, etc. + pub fn with_xvfb_shutdown( + &mut self, + f: Box SubprocessResult<()>>, + ) -> &mut Self { + self.on_xvfb_shutdown = Some(f); + self + } + + /// Attempts to spawn a child process from the `Command` provided to + /// [`SubprocessMonitor::new`]. + pub fn start(&mut self) -> SubprocessResult { + self.command + .spawn() + .map_err(|e| SubprocessError::new(self.name.clone(), SubprocessErrorType::Spawn(e))) + } + + /// Called when subprocess exit status is polled. This may be used to signal + /// an error because the exit status is bad. + pub fn check_subprocess_exit(&mut self, status: ExitStatus) -> SubprocessResult<()> { + if let Some(f) = &mut self.check_subprocess_exit { + (f)(&self.name, status) + } else { + Ok(()) + } + } + + /// Called immediately before the parent display server is being shut + /// down. This may be used to send `SIGINT` or otherwise clean up the child + /// before it is killed more forcibly. + pub fn on_xvfb_shutdown(&mut self, child: &mut Child) -> SubprocessResult<()> { + if let Some(f) = &mut self.on_xvfb_shutdown { + (f)(child) + } else { + Ok(()) + } + } + + /// Returns a callback suitable for passing to [`SubprocessMonitor::check_subprocess_exit`] + /// which requires that the process has exited cleanly. + pub fn require_clean_exit() -> Box SubprocessResult<()>> { + Box::new(|name: &str, status: ExitStatus| { + if status.success() { + Ok(()) + } else { + Err(SubprocessError::new( + String::from(name), + SubprocessErrorType::BadExit(status), + )) + } + }) + } +} + +#[cfg(test)] +mod tests { + use crate::headless::DisplayNumberRegistry; + use super::XvfbProcess; + use insta_image::assert_png_snapshot; + use std::{ + thread, + time::Duration, + }; + + /// Starts Xvfb and returns a managing object, or panics. + fn start_xvfb() -> XvfbProcess { + XvfbProcess::start_default( + DisplayNumberRegistry::next_unused_display().expect("cannot find a value for DISPLAY"), + ) + .expect("cannot start Xvfb") + } + + /// Reads a single frame of PNG data from the PNG image in `data`. Panics on + /// errors. + fn read_png_metadata(data: &[u8]) -> png::OutputInfo { + let mut reader = png::Decoder::new(std::io::Cursor::new(data)) + .read_info() + .unwrap(); + let mut buf = vec![0; reader.output_buffer_size().unwrap()]; + reader.next_frame(&mut buf).unwrap() + } + + /// Launches `xeyes(1)` with colors to make sure we're doing the right thing + /// with our color channels when encoding a screenshot tas PNG. + fn xeyes_color(xvfb: &mut XvfbProcess) { + xvfb.run_args("xeyes", "xeyes", |c| { + c.arg("-outline") + .arg("blue") + .arg("-center") + .arg("red") + .arg("-fg") + .arg("green"); + }) + .unwrap(); + thread::sleep(Duration::from_millis(100)); + } + + #[test] + fn png_blank_screenshot() { + let xvfb = start_xvfb(); + let xwd = xvfb.xwd_screenshot().unwrap(); + + assert_eq!( + xwd.visual_class(), + crate::headless::xwd::VisualClass::TrueColor + ); + + let args = crate::headless::xvfb::XvfbArgs::default(); + assert_eq!(xwd.header.depth, args.depth as u32); + assert_eq!(xwd.header.width, args.width); + assert_eq!(xwd.header.height, args.height); + + assert_png_snapshot!("blank_screen", xwd.into_png().unwrap()); + } + + #[test] + fn png_xeyes_screenshot() { + let mut xvfb = start_xvfb(); + xeyes_color(&mut xvfb); + + let compressed = xvfb.png_screenshot(); + let image_data = read_png_metadata(&compressed); + + let args = crate::headless::xvfb::XvfbArgs::default(); + assert_eq!(image_data.width, args.width); + assert_eq!(image_data.height, args.height); + + assert_png_snapshot!("xeyes", compressed); + } + + #[test] + fn png_lamp_image() { + let mut xvfb = start_xvfb(); + xvfb.run_args("xwud", "xwud", |c| { + c.arg("-in").arg("src/headless/snowlamp.xwd"); + }) + .unwrap(); + thread::sleep(Duration::from_millis(100)); + + let compressed = xvfb.png_screenshot(); + + assert_png_snapshot!("snowlamp_in_window", compressed); + } +} diff --git a/WINGs/wings-rs-tests/src/headless/xwd.rs b/WINGs/wings-rs-tests/src/headless/xwd.rs new file mode 100644 index 00000000..2f113d40 --- /dev/null +++ b/WINGs/wings-rs-tests/src/headless/xwd.rs @@ -0,0 +1,325 @@ +//! Provides basic support for rendering dumps of X11 windows made with [the `xwud` utility](https://gitlab.freedesktop.org/xorg/app/xwud/-/blob/master/xwud.c?ref_type=heads). + +use std::{ + ffi::CString, + io::Cursor, + mem, +}; + +const SUPPORTED_XWD_VERSION: u32 = 7; + +/// Header for `xwd`-style dumps of X11 windows. +/// +/// This is taken from `/usr/include/X11/XWDFile.h` on a Debian system. +#[derive(Clone)] +#[repr(C)] +pub struct XwdHeader { + /// Total header size (including null-terminated window name). + pub size: u32, + /// Version of `xwd` that this dump came from. + pub version: u32, + pub _format: u32, + /// Bit depth of the X11 server. + pub depth: u32, + /// Image width. + pub width: u32, + /// Image height. + pub height: u32, + pub _x_offset: u32, + pub _byte_order: u32, + pub _bitmap_unit: u32, + pub _bitmap_bit_order: u32, + pub _bitmap_pad: u32, + pub bits_per_pixel: u32, + pub _bytes_per_line: u32, + /// X11 visual class for this window. See [`XwdImage::visual_class`] for a + /// more human-interpretable value. + pub visual_class: u32, + /// Bitmask for the red channel in pixel data. + pub red_mask: u32, + /// Bitmask for the green channel in pixel data. + pub green_mask: u32, + /// Bitmask for the blue channel in pixel data. + pub blue_mask: u32, + /// Number of bits per RGB tuple in color data. (E.g., 24-bit color may + /// actually be padded to 4 bytes.) + pub bits_per_rgb: u32, + pub _colormap_entries: u32, + /// Number of colors in the colormap for the window that this dump came from. + /// + /// Note that a colormap may exist but be unused (if the visual class is not + /// one that uses a colormap). + pub ncolors: u32, + pub _window_width: u32, + pub _window_height: u32, + pub _window_x: u32, + pub _window_y: u32, + pub _window_border_width: u32, +} + +const HEADER_SIZE: u32 = mem::size_of::() as u32; + +/// Color data for an entry in a colormap. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(C)] +pub struct XwdColor { + pixel: u32, + red: u16, + green: u16, + blue: u16, + flags: u8, + pad: u8, +} + +fn next_u32(bytes: &mut impl Iterator) -> u32 { + let bytes = [ + bytes.next().unwrap(), + bytes.next().unwrap(), + bytes.next().unwrap(), + bytes.next().unwrap(), + ]; + u32::from_be_bytes(bytes) +} + +fn next_u16(bytes: &mut impl Iterator) -> u16 { + let bytes = [bytes.next().unwrap(), bytes.next().unwrap()]; + u16::from_be_bytes(bytes) +} + +/// Describes how pixel data is represented in an `xwd` dump. +/// +/// See descriptions of visual classes at +/// and [the official +/// documentation](https://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#visual_information) +/// for more information. +#[derive(Clone, Copy, Eq, Debug, PartialEq)] +pub enum VisualClass { + StaticGray, + GrayScale, + StaticColor, + PseudoColor, + TrueColor, + DirectColor, +} + +impl XwdHeader { + /// Decodes an `XwdHeader` from `bytes`, panicking on failure. + /// + /// Leaves `bytes` pointing to the start of the window name. + pub fn read(bytes: &mut impl Iterator) -> XwdHeader { + // This layout might change in the future, but let's just go with it for now. + XwdHeader { + size: next_u32(bytes), + version: next_u32(bytes), + _format: next_u32(bytes), + depth: next_u32(bytes), + width: next_u32(bytes), + height: next_u32(bytes), + _x_offset: next_u32(bytes), + _byte_order: next_u32(bytes), + _bitmap_unit: next_u32(bytes), + _bitmap_bit_order: next_u32(bytes), + _bitmap_pad: next_u32(bytes), + bits_per_pixel: next_u32(bytes), + _bytes_per_line: next_u32(bytes), + visual_class: next_u32(bytes), + red_mask: next_u32(bytes), + green_mask: next_u32(bytes), + blue_mask: next_u32(bytes), + bits_per_rgb: next_u32(bytes), + _colormap_entries: next_u32(bytes), + ncolors: next_u32(bytes), + _window_width: next_u32(bytes), + _window_height: next_u32(bytes), + _window_x: next_u32(bytes), + _window_y: next_u32(bytes), + _window_border_width: next_u32(bytes), + } + } +} + +impl XwdColor { + /// Reads an `XwdColor` from `bytes`, panicking on failure. + /// + /// Leaves `bytes` pointing to the next byte after the end of the color + /// definition. + pub fn read(bytes: &mut impl Iterator) -> XwdColor { + XwdColor { + pixel: next_u32(bytes), + red: next_u16(bytes), + green: next_u16(bytes), + blue: next_u16(bytes), + flags: bytes.next().unwrap(), + pad: bytes.next().unwrap(), + } + } +} + +/// A decoded `xwd` dump. +pub struct XwdImage { + /// Header with image metadata. + pub header: XwdHeader, + /// Name of the X11 window that the image came from. + pub name: CString, + /// Colormap data for the X11 window that the image came from. + /// + /// Note that this may be populated even if it is unused (because the + /// window's visual class is one that does not use a colormap). + pub colors: Vec, + /// Pixel data for the image. + /// + /// This may be indices pointing into `colors`, or it may be actual pixel + /// values. + pub pixels: Vec, +} + +impl XwdImage { + /// Reads an `XwdImage` from `bytes`, panicking on failure. + pub fn read(bytes: &mut impl Iterator) -> XwdImage { + let header = XwdHeader::read(bytes); + if header.version != SUPPORTED_XWD_VERSION { + panic!( + "header version {} is not supported. only version {} files are supported.", + header.version, SUPPORTED_XWD_VERSION + ); + } + let name = Self::read_name(&header, bytes); + let colors = Self::read_colors(&header, bytes); + let pixels = bytes.collect(); + + XwdImage { + header, + name, + colors, + pixels, + } + } + + /// Reads a colormap for the image described by `header` from `bytes`. + /// + /// `bytes` must point at the start of the colormap data. Leaves `bytes` + /// pointing at the first byte of the next item in the data stream. + pub fn read_colors(header: &XwdHeader, bytes: &mut impl Iterator) -> Vec { + let mut colors = Vec::with_capacity(header.ncolors as usize); + for _ in 0..header.ncolors { + colors.push(XwdColor::read(bytes)); + } + colors + } + + /// Reads the X11 window name from `bytes`. + /// + /// `bytes` must point at the start of the window name. Leaves `bytes` + /// pointing at the first byte of the next item in the data stream. + /// + /// Note that the window name is a null-terminated string, but `header.size` + /// (which is supposed to be equal to the size of the header structure plus + /// the window name) may actually be longer than `strlen(name) + + /// sizeof(HeaderType)`. When that is the case, the extra padding after the + /// first null byte in the window name will be passed over silently. + pub fn read_name(header: &XwdHeader, bytes: &mut impl Iterator) -> CString { + if header.size <= HEADER_SIZE { + panic!( + "Invalid header size {} (smaller than header struct size {})", + header.size, HEADER_SIZE + ); + } + let mut buf = Vec::new(); + let mut found_nul = false; + for _ in 0..header.size - HEADER_SIZE { + let b = bytes.next().unwrap(); + if b == 0 { + if found_nul { + continue; + } else { + buf.push(b); + found_nul = true; + } + } else { + buf.push(b); + } + } + CString::from_vec_with_nul(buf).unwrap() + } + + /// Returns the visual class for this window dump. + pub fn visual_class(&self) -> VisualClass { + match self.header.visual_class { + 0 => VisualClass::StaticGray, + 1 => VisualClass::GrayScale, + 2 => VisualClass::StaticColor, + 3 => VisualClass::PseudoColor, + 4 => VisualClass::TrueColor, + 5 => VisualClass::DirectColor, + _ => panic!( + "unrecognized X11 visual class: {}", + self.header.visual_class + ), + } + } + + /// Encodes this image as a PNG, consumes `self` in the process (because the + /// image data is reused during the encoding process). + /// + /// Note that only [`VisualClass::TrueColor`] images with a specific pixel + /// format (24-bit color packed into 32-bit segments with BGR ordering) are + /// supported. + pub fn into_png(self) -> Result, png::EncodingError> { + match self.visual_class() { + VisualClass::TrueColor => into_png_true_color(self.header, self.pixels), + _ => todo!("X11 visual classes other than TrueColor are not yet supported"), + } + } +} + +fn into_png_true_color( + header: XwdHeader, + mut pixels: Vec, +) -> Result, png::EncodingError> { + if header.depth != 24 { + todo!("pixmap color depths other than 24-bit are not yet supported"); + } + if !(header.red_mask == 0xff0000 + && header.green_mask == 0x00ff00 + && header.blue_mask == 0x0000ff) + { + todo!("color orderings other than RGB are not yet supported"); + } + if header.bits_per_rgb == 32 { + todo!("bits per rgb triplet other than 32 are not yet supported"); + } + + let mut out = Cursor::new(Vec::::new()); + let mut encoder = png::Encoder::new(&mut out, header.width, header.height); + encoder.set_color(png::ColorType::Rgba); + encoder.set_depth(png::BitDepth::Eight); + encoder.set_compression(png::Compression::High); + + for pixel in pixels.chunks_mut(4) { + let blue = pixel[0]; + let green = pixel[1]; + let red = pixel[2]; + pixel[0] = red; + pixel[1] = green; + pixel[2] = blue; + pixel[3] = 0xFF; + } + + let mut writer = encoder.write_header()?; + writer.write_image_data(&pixels)?; + writer.finish()?; + + Ok(out.into_inner()) +} + +#[cfg(test)] +mod tests { + use super::XwdImage; + use insta_image::assert_png_snapshot; + + #[test] + fn png_encode() { + let snowlamp_xwd = XwdImage::read(&mut include_bytes!("snowlamp.xwd").into_iter().copied()); + assert_png_snapshot!("snowlamp_encoded", snowlamp_xwd.into_png().unwrap()); + } +} diff --git a/WINGs/wings-rs-tests/src/lib.rs b/WINGs/wings-rs-tests/src/lib.rs new file mode 100644 index 00000000..0baad46e --- /dev/null +++ b/WINGs/wings-rs-tests/src/lib.rs @@ -0,0 +1,185 @@ +pub mod headless; + +use headless::{xvfb::XvfbProcess, DisplayNumberRegistry}; +use std::{ + env, + ffi::{c_char, c_int, CStr, CString}, + ptr::{self, NonNull}, + sync::Mutex, +}; +use wings_rs::WINGsP::{WMHandleEvent, WMInitializeApplication, WMReleaseApplication, WMScreen}; + +static APPLICATION_COUNT: Mutex = Mutex::new(0); + +/// Stubbed wrapper for WMApplication. +pub struct HeadlessApplication { + /// The headless X server process. + pub xvfb: XvfbProcess, + /// An open client handle to the headless X server. + pub display: NonNull, + /// A fully initialized `WMScreen` for an application running on the + /// headless X server. + pub screen: NonNull, +} + +impl HeadlessApplication { + /// Starts a headless X server and calls `WMInitializeApplication` if no + /// WINGs application is active. + pub fn new() -> Self { + static PROGNAME: &'static CStr = c"Test@eqweq_ewq$eqw"; + + let xvfb = XvfbProcess::start_default( + DisplayNumberRegistry::next_unused_display() + .expect("cannot allocate a value for DISPLAY"), + ) + .expect("cannot start Xvfb"); + + { + let mut application_count = APPLICATION_COUNT.lock().unwrap(); + if *application_count == 0 { + unsafe { + let mut argv: Vec<*mut c_char> = + vec![PROGNAME.as_ptr().cast::() as *mut c_char]; + let mut argc: c_int = 1; + WMInitializeApplication( + PROGNAME.as_ptr().cast::(), + &mut argc as *mut _, + argv.as_mut_ptr(), + ); + } + } + *application_count += 1; + } + + let display_str = CString::new(format!(":{}", xvfb.display())).unwrap(); + let display = + NonNull::new(unsafe { x11::xlib::XOpenDisplay(display_str.as_ptr()) }).unwrap(); + let screen = WMScreen::new(&display).unwrap(); + + HeadlessApplication { + xvfb, + display, + screen, + } + } + + /// Pumps the WUtil and X11 event queues, hackily. + /// + /// Runs WUtil event handlers that should be run by `now`, pumps the X11 + /// event queue, dispatches the next pending event (if any), and runs + /// WUtil idle handlers (if no X11 events are available). + /// + /// Returns `true` if more events are pending. (This does not account for + /// WUtils timer events that might need to fire, since the future time when + /// `pump_event_queue` will next be called cannot be known.) + /// + /// This is somewhat hacky (because it does not match the WINGs main loop + /// logic exactly), so it should only be used by tests. + pub fn pump_event_queue(&mut self, now: std::time::Instant) -> bool { + let display = self.display.as_ptr(); + wutil_rs::handlers::with_global_handlers(|handlers| handlers.check_timer_handlers(now)); + + unsafe { + x11::xlib::XSync(display, 0); + if x11::xlib::XPending(display) > 0 { + let mut event = x11::xlib::XEvent { type_: 0 }; + x11::xlib::XNextEvent(display, &mut event as *mut _); + WMHandleEvent(&mut event as *mut _); + } else { + wutil_rs::handlers::run_global_idle_handlers(); + } + + x11::xlib::XSync(display, 0); + if x11::xlib::XPending(display) > 0 { + return true; + } + wutil_rs::handlers::with_global_handlers(|handlers| handlers.has_idle_handlers()) + } + } +} + +impl Drop for HeadlessApplication { + fn drop(&mut self) { + unsafe { + x11::xlib::XCloseDisplay(self.display.as_ptr()); + // Leak self.screen, since WINGs doesn't provide a cleanup function. + } + let mut application_count = APPLICATION_COUNT.lock().unwrap(); + if *application_count <= 1 { + *application_count = 0; + unsafe { + WMReleaseApplication(); + } + } else { + *application_count -= 1; + } + self.xvfb.shutdown().unwrap(); + } +} + +/// Simple wrapper for demo WINGs applications. +/// +/// This handles calling `WMInitializeApplication`, which operates on a +/// singleton behind the scenes and wants to be passed command line arguments. +/// +/// When the last instantiated `LiveApplication` is dropped, +/// `WMReleaseApplication` is called automatically. +pub struct LiveApplication { + /// Live X11 `Display` that the application is running on. + pub display: NonNull, + /// Fully intialized `WMScreen` for the application. + /// + /// This is leaked when the `LiveApplication` is dropped because WINGs does + /// not provide a deletion function. + pub screen: NonNull, +} + +impl LiveApplication { + /// Creates a new application wrapper and initializes the global + /// `WMApplication` if necessary. + pub fn new(name: &str) -> Self { + let mut application_count = APPLICATION_COUNT.lock().unwrap(); + if *application_count > 0 { + panic!("application already started!"); + } + let name = CString::new(name).expect("invalid program name"); + unsafe { + let mut argv: Vec = vec![name]; + let name_ptr = argv[0].as_ptr().cast::(); + for arg in env::args() { + argv.push(CString::new(arg).expect("invalid argument string")); + } + let mut argv_ptrs: Vec<*mut c_char> = argv + .iter_mut() + .map(|a| a.as_ptr().cast::() as *mut c_char) + .collect(); + let mut argc: c_int = argv_ptrs.len().try_into().expect("invalid argument count"); + WMInitializeApplication(name_ptr, &mut argc as *mut _, argv_ptrs.as_mut_ptr()); + } + *application_count = 1; + + let display = NonNull::new(unsafe { x11::xlib::XOpenDisplay(ptr::null_mut()) }) + .expect("could not connect to X11 display"); + let screen = WMScreen::new(&display).unwrap(); + + LiveApplication { display, screen } + } +} + +impl Drop for LiveApplication { + fn drop(&mut self) { + unsafe { + x11::xlib::XCloseDisplay(self.display.as_ptr()); + // Leak self.screen, since WINGs doesn't provide a cleanup function. + } + let mut application_count = APPLICATION_COUNT.lock().unwrap(); + if *application_count <= 1 { + *application_count = 0; + unsafe { + WMReleaseApplication(); + } + } else { + *application_count -= 1; + } + } +} diff --git a/WINGs/wings-rs/Cargo.toml b/WINGs/wings-rs/Cargo.toml index 689a9201..3d12b5ed 100644 --- a/WINGs/wings-rs/Cargo.toml +++ b/WINGs/wings-rs/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [lib] -crate-type = ["staticlib"] +crate-type = ["staticlib", "rlib"] [dependencies] libc = "0.2.177" diff --git a/WINGs/wings-rs/Makefile.am b/WINGs/wings-rs/Makefile.am index 73afa18a..aa9e1b23 100644 --- a/WINGs/wings-rs/Makefile.am +++ b/WINGs/wings-rs/Makefile.am @@ -13,7 +13,15 @@ RUST_EXTRA = \ Cargo.toml src/WINGsP.rs: ../WINGs/WINGsP.h ../../wrlib/wraster.h ../WINGs/WINGs.h ../WINGs/WUtil.h Makefile patch_WINGsP.sh - $(BINDGEN) ../WINGs/WINGsP.h --ignore-functions --allowlist-type "^W_.+|^WM(View|Array|DragOperationType|Point|Data|OpenPanel|SavePanel|HashTable|DraggingInfo|SelectionProcs|Rect|EventProc|Widget|Size|Color|Pixmap|FilePanel)|R(Context|ContextAttributes|Image|RenderingMode|ScalingFilter|StdColormapMode|ImageFormat|Color)|_WINGsConfiguration" --no-recursive-allowlist -o src/WINGsP.rs -- @PANGO_CFLAGS@ -I../../wrlib -I.. && ./patch_WINGsP.sh src/WINGsP.rs + $(BINDGEN) ../WINGs/WINGsP.h \ + --no-recursive-allowlist \ + --allowlist-type "^W_.+|^WM(View|Array|DragOperationType|Point|Data|OpenPanel|SavePanel|HashTable|DraggingInfo|SelectionProcs|Rect|EventProc|Widget|Size|Color|Pixmap|FilePanel)|R(Context|ContextAttributes|Image|RenderingMode|ScalingFilter|StdColormapMode|ImageFormat|Color)|_WINGsConfiguration" \ + --allowlist-type "^WM(FontPanel|Screen|Button)" \ + --allowlist-function "^WMCreateScreen|^WM(Get|Show)FontPanel|^WMCreateCommandButton|^WM(Initialize|Release)Application|^WMScreenMainLoop|^WMHandleEvent" \ + -o src/WINGsP.rs -- \ + @PANGO_CFLAGS@ \ + -I../../wrlib \ + -I.. && ./patch_WINGsP.sh src/WINGsP.rs target/debug/libwings_rs.a: $(RUST_SOURCES) $(RUST_EXTRA) $(CARGO) build diff --git a/WINGs/wings-rs/src/screen.rs b/WINGs/wings-rs/src/screen.rs index 8d5170e9..c887875a 100644 --- a/WINGs/wings-rs/src/screen.rs +++ b/WINGs/wings-rs/src/screen.rs @@ -1,15 +1,20 @@ use crate::{ - WINGsP::W_Screen, + WINGsP::{WMScreen, WMCreateScreen}, font::{Font, FontName}, }; use std::{ collections::{HashMap, hash_map::Entry}, ffi::c_void, + ptr::NonNull, rc::Rc, }; -impl W_Screen { +impl WMScreen { + pub fn new(display: &NonNull) -> Option> { + NonNull::new(unsafe { WMCreateScreen(display.as_ptr(), x11::xlib::XDefaultScreen(display.as_ptr())) }) + } + fn font_cache_mut(&mut self) -> &mut HashMap> { if self.fontCache.is_null() { self.fontCache = (Box::leak(Box::new(HashMap::>::new())) @@ -50,13 +55,13 @@ impl W_Screen { #[cfg(test)] mod test { - use crate::WINGsP::W_Screen; + use crate::WINGsP::WMScreen; use std::mem::MaybeUninit; #[test] fn font_cache_init() { - let mut screen: W_Screen = unsafe { MaybeUninit::zeroed().assume_init() }; + let mut screen: WMScreen = unsafe { MaybeUninit::zeroed().assume_init() }; let cache = screen.font_cache_mut(); assert!(cache.is_empty()); } diff --git a/configure.ac b/configure.ac index 61761963..93c42684 100644 --- a/configure.ac +++ b/configure.ac @@ -933,9 +933,9 @@ AC_CONFIG_FILES( wutil-rs/Makefile dnl WINGs toolkit - WINGs/Makefile WINGs/wings-rs/Makefile WINGs/WINGs/Makefile WINGs/po/Makefile - WINGs/Documentation/Makefile WINGs/Resources/Makefile WINGs/Extras/Makefile - WINGs/Examples/Makefile WINGs/Tests/Makefile + WINGs/Makefile WINGs/wings-rs/Makefile WINGs/WINGs/Makefile WINGs/wings-rs-tests/Makefile + WINGs/po/Makefile WINGs/Documentation/Makefile WINGs/Resources/Makefile + WINGs/Extras/Makefile WINGs/Examples/Makefile WINGs/Tests/Makefile dnl Rust implementation of Window Maker core wmaker-rs/Makefile diff --git a/wutil-rs/Cargo.toml b/wutil-rs/Cargo.toml index 0d3e85dd..d9f7277b 100644 --- a/wutil-rs/Cargo.toml +++ b/wutil-rs/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [lib] -crate-type = ["staticlib"] +crate-type = ["staticlib","rlib"] [build-dependencies] cc = "1.0" diff --git a/wutil-rs/src/handlers.rs b/wutil-rs/src/handlers.rs index d9927d7e..41ea1956 100644 --- a/wutil-rs/src/handlers.rs +++ b/wutil-rs/src/handlers.rs @@ -158,6 +158,11 @@ impl HandlerQueues { QueueStatus::Pending } } + + /// Returns `true` if any idle handlers need to be run. + pub fn has_idle_handlers(&self) -> bool { + !self.idle_handlers.is_empty() + } } /// Runs each of `handlers` that should run before `now` and returns those that @@ -209,11 +214,11 @@ struct IdleHandler { static DEFAULT_HANDLERS: Mutex = Mutex::new(HandlerQueues::new()); -fn with_global_handlers(f: impl FnOnce(&mut HandlerQueues) -> R) -> R { +pub fn with_global_handlers(f: impl FnOnce(&mut HandlerQueues) -> R) -> R { f(&mut DEFAULT_HANDLERS.try_lock().unwrap()) } -fn run_global_idle_handlers() -> QueueStatus { +pub fn run_global_idle_handlers() -> QueueStatus { // Move handlers out of the global queue because it is locked while // with_global_handlers is running, and a callback may try to schedule // another callback or perform some other operation on the global queue. @@ -226,10 +231,10 @@ fn run_global_idle_handlers() -> QueueStatus { (h.callback)(); } with_global_handlers(|handlers| { - if handlers.idle_handlers.is_empty() { - QueueStatus::Empty - } else { + if handlers.has_idle_handlers() { QueueStatus::Pending + } else { + QueueStatus::Empty } }) } -- 2.39.5