Вот идея. У меня есть основной цикл событий, в котором я хочу добавить тайм-аут для опроса нового устройства Bluetooth каждые 5 секунд, поскольку GTK4 — это всего лишь синхронная библиотека. Я написал асинхронную функцию, используя bluer для перечисления устройств Bluetooth. Эта программа отлично работает в своей собственной программе с асинхронной основной функцией. Если взять ту же функцию и перенести ее в более крупный проект с базовым пользовательским интерфейсом GTK, по какой-то причине это не приведет к добавлению каких-либо устройств в очередь сообщений.
Очередь сообщений в этом контексте Arc. Просто стандартный мьютекс, используемый потоками. Это также происходит с sync_channels и обычными каналами.
Основной поток пытается заблокировать мьютекс, читает его, а затем снимает блокировку с помощью drop(Mutex)< /код>. Событие в основном цикле выполняется раз в 5 секунд. В остальное время наша асинхронная функция блокирует мьютекс и пытается поместить имя устройства в очередь сообщений, чтобы его мог прочитать основной поток.
Вот код, который у меня есть. далеко.
Код: Выделить всё
pub fn build_ui(app: Application) -> Application {
app.connect_activate(move |app| {
let mut queue = Arc::new(Mutex::new(Vec::::new()));
let mlayout = Grid::builder()
.height_request(700)
.width_request(200)
.build();
let text_buf = TextBuffer::new(None);
let text_view = TextView::builder()
.buffer(&text_buf)
.width_request(200)
.height_request(600)
.vexpand(true)
.build();
let mwindow = ApplicationWindow::builder()
.application(app)
.resizable(false)
.width_request(200)
.height_request(700)
.child(&mlayout)
.build();
let dev_list = Frame::builder()
.height_request(700)
.width_request(200)
.vexpand(true)
.child(&text_view)
.build();
let title = Label::builder()
.label("Device List")
.css_name("Title")
.width_request(200)
.height_request(50)
.justify(gtk4::Justification::Center)
.build();
mlayout.attach(&title, 0, 0, 200, 50);
mlayout.attach(&dev_list, 0, 50, 200, 1);
mwindow.init_layer_shell();
mwindow.set_anchor(Edge::Right, true);
mwindow.set_anchor(Edge::Top, true);
mwindow.present();
let txqueue = Arc::clone(&queue);
thread::spawn(move || async {
blue_init(txqueue).await;
});
gtk4::glib::timeout_add_local(Duration::from_secs(5), move || {
match queue.clone().try_lock() {
Ok(dev) => {
println!("{:#?}", dev);
drop(dev);
ControlFlow::Continue
}
_ => ControlFlow::Continue,
}
});
});
app
}
pub async fn blue_init(queue: Arc) {
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
runtime.spawn(async move {
let session = Session::new().await.unwrap();
let adapter = session.default_adapter().await.unwrap();
let discover = adapter.discover_devices().await.unwrap();
pin_mut!(discover);
while let Some(evt) = discover.next().await {
match evt {
AdapterEvent::DeviceAdded(addr) => {
let device = adapter.device(addr).unwrap();
let name = device.alias().await.unwrap();
match queue.try_lock() {
Ok(mut data) => {
data.push(name);
drop(data);
}
_ => {}
}
}
_ => {}
}
}
});
Подробнее здесь: https://stackoverflow.com/questions/788 ... event-loop
Мобильная версия