From a34c1c4134f9fdb0a5a5e7163b4f80b511c005a9 Mon Sep 17 00:00:00 2001 From: fbrouille Date: Wed, 28 May 2025 18:37:09 +0000 Subject: [PATCH] Add gio::FileMonitor subclass Signed-off-by: fbrouille --- Cargo.lock | 175 +++++++++++++-------- gio/Cargo.toml | 1 + gio/src/subclass/file_monitor.rs | 254 +++++++++++++++++++++++++++++++ gio/src/subclass/mod.rs | 2 + 4 files changed, 372 insertions(+), 60 deletions(-) create mode 100644 gio/src/subclass/file_monitor.rs diff --git a/Cargo.lock b/Cargo.lock index e262475b334f..3b77c040485a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,18 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-tls" version = "0.13.0" @@ -101,9 +113,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "shlex", ] @@ -153,18 +165,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.31" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.31" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstyle", "clap_lex", @@ -176,6 +188,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "criterion" version = "0.6.0" @@ -242,9 +263,9 @@ checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "either" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" @@ -254,14 +275,35 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", ] +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -411,9 +453,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -422,20 +464,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "gio" version = "0.21.0" dependencies = [ + "async-channel", "futures", "futures-channel", "futures-core", @@ -577,9 +620,9 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", @@ -599,9 +642,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.7.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -627,9 +670,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" @@ -649,9 +692,9 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "libc", @@ -661,9 +704,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "lock_api" @@ -677,9 +720,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -698,15 +741,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "pango" @@ -756,6 +799,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -852,6 +901,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rayon" version = "1.10.0" @@ -874,9 +929,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags", ] @@ -912,13 +967,13 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" -version = "0.17.11" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -926,9 +981,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.1" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", @@ -970,15 +1025,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -991,9 +1046,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea091f6cac2595aa38993f04f4ee692ed43757035c36e67c180b6828356385b1" +checksum = "22b2d775fb28f245817589471dd49c5edf64237f4a19d10ce9a92ff4651a27f4" dependencies = [ "sdd", ] @@ -1016,24 +1071,24 @@ dependencies = [ [[package]] name = "sdd" -version = "3.0.7" +version = "3.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07779b9b918cc05650cb30f404d4d7835d26df37c235eded8a6832e2fb82cca" +checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21" [[package]] name = "serde" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.218" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -1150,7 +1205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.2", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1226,9 +1281,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "untrusted" @@ -1266,9 +1321,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -1453,18 +1508,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.3" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ "bitflags", ] diff --git a/gio/Cargo.toml b/gio/Cargo.toml index 6a858bc0aeec..35cbc94b1227 100644 --- a/gio/Cargo.toml +++ b/gio/Cargo.toml @@ -48,6 +48,7 @@ smallvec = "1" [dev-dependencies] futures = "0.3" futures-util = { version = "0.3", features = ["io"] } +async-channel = "2.3" gir-format-check.workspace = true serial_test = "3" diff --git a/gio/src/subclass/file_monitor.rs b/gio/src/subclass/file_monitor.rs new file mode 100644 index 000000000000..f30cabf16761 --- /dev/null +++ b/gio/src/subclass/file_monitor.rs @@ -0,0 +1,254 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::{prelude::*, subclass::prelude::*, translate::*}; + +use crate::{ffi, File, FileMonitor, FileMonitorEvent}; + +// Support custom implementation of virtual functions defined in `gio::ffi::GFileMonitorClass`. +pub trait FileMonitorImpl: ObjectImpl + ObjectSubclass> { + fn changed(&self, file: &File, other_file: Option<&File>, event_type: FileMonitorEvent) { + self.parent_changed(file, other_file, event_type) + } + + fn cancel(&self) { + self.parent_cancel() + } +} + +// Support parent implementation of virtual functions defined in `gio::ffi::GFileMonitorClass`. +pub trait FileMonitorImplExt: FileMonitorImpl { + fn parent_changed(&self, file: &File, other_file: Option<&File>, event_type: FileMonitorEvent) { + unsafe { + let data = Self::type_data(); + let parent_class = data.as_ref().parent_class() as *const ffi::GFileMonitorClass; + + if let Some(f) = (*parent_class).changed { + f( + self.obj().unsafe_cast_ref::().to_glib_none().0, + file.to_glib_none().0, + other_file.to_glib_none().0, + event_type.into_glib(), + ); + } + } + } + + fn parent_cancel(&self) { + unsafe { + let data = Self::type_data(); + let parent_class = data.as_ref().parent_class() as *const ffi::GFileMonitorClass; + + let f = (*parent_class) + .cancel + .expect("No parent class implementation for \"cancel\""); + + let _ = f(self.obj().unsafe_cast_ref::().to_glib_none().0); + } + } +} + +impl FileMonitorImplExt for T {} + +// Implement virtual functions defined in `gio::ffi::GFileMonitorClass`. +unsafe impl IsSubclassable for FileMonitor { + fn class_init(class: &mut ::glib::Class) { + Self::parent_class_init::(class); + + let klass = class.as_mut(); + klass.changed = Some(changed::); + klass.cancel = Some(cancel::); + } +} + +unsafe extern "C" fn changed( + monitor: *mut ffi::GFileMonitor, + file: *mut ffi::GFile, + other_file: *mut ffi::GFile, + event_type: ffi::GFileMonitorEvent, +) { + let instance = &*(monitor as *mut T::Instance); + let imp = instance.imp(); + let other_file = Option::::from_glib_none(other_file); + + imp.changed( + &from_glib_borrow(file), + other_file.as_ref(), + from_glib(event_type), + ); +} + +unsafe extern "C" fn cancel( + monitor: *mut ffi::GFileMonitor, +) -> glib::ffi::gboolean { + let instance = &*(monitor as *mut T::Instance); + let imp = instance.imp(); + + imp.cancel(); + + // vfunc must return true as specified in documentation. + // https://docs.gtk.org/gio/vfunc.FileMonitor.cancel.html + true.into_glib() +} + +#[cfg(test)] +mod tests { + // The following tests rely on a custom type `MyCustomFileMonitor` that extends another custom type `MyFileMonitor`. + // For each virtual method defined in class `gio::ffi::GFileMonitorClass`, a test checks that `MyCustomFileMonitor` and `MyFileMonitor` return the same results. + + use super::*; + use crate::prelude::*; + + // Define `MyCustomFileMonitor` as a subclass of `MyFileMonitor`. + mod imp { + use super::*; + + #[derive(Default)] + pub struct MyFileMonitor; + + #[glib::object_subclass] + impl ObjectSubclass for MyFileMonitor { + const NAME: &'static str = "MyFileMonitor"; + type Type = super::MyFileMonitor; + type ParentType = FileMonitor; + } + + impl ObjectImpl for MyFileMonitor {} + + // Implements `FileMonitorImpl` with custom implementation. + impl FileMonitorImpl for MyFileMonitor { + fn cancel(&self) {} + } + + #[derive(Default)] + pub struct MyCustomFileMonitor; + + #[glib::object_subclass] + impl ObjectSubclass for MyCustomFileMonitor { + const NAME: &'static str = "MyCustomFileMonitor"; + type Type = super::MyCustomFileMonitor; + type ParentType = super::MyFileMonitor; + } + + impl ObjectImpl for MyCustomFileMonitor {} + + // Implements `FileMonitorImpl` with default implementation, which calls the parent's implementation. + impl FileMonitorImpl for MyCustomFileMonitor {} + + impl MyFileMonitorImpl for MyCustomFileMonitor {} + } + + glib::wrapper! { + pub struct MyFileMonitor(ObjectSubclass) @extends FileMonitor; + } + + pub trait MyFileMonitorImpl: + ObjectImpl + ObjectSubclass + IsA> + { + } + + // To make this class subclassable we need to implement IsSubclassable + unsafe impl IsSubclassable for MyFileMonitor {} + + glib::wrapper! { + pub struct MyCustomFileMonitor(ObjectSubclass) @extends MyFileMonitor, FileMonitor; + } + + #[test] + fn file_monitor_changed() { + // run test in a main context dedicated and configured as the thread default one + let _ = glib::MainContext::new().with_thread_default(|| { + // invoke `MyCustomFileMonitor` implementation of `gio::ffi::GFileMonitorClass::cancel` + let my_custom_file_monitor = glib::Object::new::(); + let rx = { + let (tx, rx) = async_channel::bounded(1); + my_custom_file_monitor.connect_changed(move |_, file, other_file, event_type| { + let res = glib::MainContext::ref_thread_default().block_on(tx.send(( + file.uri(), + other_file.map(File::uri), + event_type, + ))); + assert!(res.is_ok(), "{}", res.err().unwrap()); + }); + rx + }; + // emit an event + my_custom_file_monitor.emit_event( + &File::for_uri("child"), + None::<&File>, + FileMonitorEvent::Created, + ); + let res = glib::MainContext::ref_thread_default().block_on(rx.recv()); + assert!(res.is_ok(), "{}", res.err().unwrap()); + let event = res.unwrap(); + + // invoke `MyFileMonitor` implementation of `gio::ffi::GFileMonitorClass::cancel` + let my_file_monitor = glib::Object::new::(); + let expected_rx = { + let (tx, rx) = async_channel::bounded(1); + my_file_monitor.connect_changed(move |_, file, other_file, event_type| { + let res = glib::MainContext::ref_thread_default().block_on(tx.send(( + file.uri(), + other_file.map(File::uri), + event_type, + ))); + assert!(res.is_ok(), "{}", res.err().unwrap()); + }); + rx + }; + // emit an event + my_file_monitor.emit_event( + &File::for_uri("child"), + None::<&File>, + FileMonitorEvent::Created, + ); + let res = glib::MainContext::ref_thread_default().block_on(expected_rx.recv()); + assert!(res.is_ok(), "{}", res.err().unwrap()); + let expected_event = res.unwrap(); + + // both results should equal + assert_eq!(event, expected_event); + }); + } + + #[test] + fn file_monitor_cancel() { + // run test in a main context dedicated and configured as the thread default one + let _ = glib::MainContext::new().with_thread_default(|| { + // invoke `MyCustomFileMonitor` implementation of `gio::ffi::GFileMonitorClass::cancel` + let my_custom_file_monitor = glib::Object::new::(); + let rx = { + let (tx, rx) = async_channel::bounded(1); + my_custom_file_monitor.connect_cancelled_notify(move |_| { + let res = glib::MainContext::ref_thread_default().block_on(tx.send(true)); + assert!(res.is_ok(), "{}", res.err().unwrap()); + }); + rx + }; + let cancelled = my_custom_file_monitor.cancel(); + let res = glib::MainContext::ref_thread_default().block_on(rx.recv()); + assert!(res.is_ok(), "{}", res.err().unwrap()); + let notified = res.unwrap(); + assert_eq!(cancelled, notified); + + // invoke `MyFileMonitor` implementation of `gio::ffi::GFileMonitorClass::cancel` + let my_file_monitor = glib::Object::new::(); + let expected_rx = { + let (tx, rx) = async_channel::bounded(1); + my_file_monitor.connect_cancelled_notify(move |_| { + let res = glib::MainContext::ref_thread_default().block_on(tx.send(true)); + assert!(res.is_ok(), "{}", res.err().unwrap()); + }); + rx + }; + let expected_cancelled = my_file_monitor.cancel(); + let res = glib::MainContext::ref_thread_default().block_on(expected_rx.recv()); + assert!(res.is_ok(), "{}", res.err().unwrap()); + let expected_notified = res.unwrap(); + assert_eq!(expected_cancelled, expected_notified); + + // both results should equal + assert_eq!(cancelled, expected_cancelled); + assert_eq!(notified, expected_notified); + }); + } +} diff --git a/gio/src/subclass/mod.rs b/gio/src/subclass/mod.rs index 791d1752a8c8..cbf526ef248a 100644 --- a/gio/src/subclass/mod.rs +++ b/gio/src/subclass/mod.rs @@ -4,6 +4,7 @@ mod action_group; mod action_map; mod application; mod async_initable; +mod file_monitor; mod initable; mod input_stream; mod io_stream; @@ -23,6 +24,7 @@ pub mod prelude { action_map::{ActionMapImpl, ActionMapImplExt}, application::{ApplicationImpl, ApplicationImplExt}, async_initable::{AsyncInitableImpl, AsyncInitableImplExt}, + file_monitor::{FileMonitorImpl, FileMonitorImplExt}, initable::{InitableImpl, InitableImplExt}, input_stream::{InputStreamImpl, InputStreamImplExt}, io_stream::{IOStreamImpl, IOStreamImplExt},