diff options
| author | dyknon dyknonr5fjp | 2025-02-24 18:58:32 +0900 |
|---|---|---|
| committer | dyknon dyknonr5fjp | 2025-02-24 18:58:32 +0900 |
| commit | 6ecbf0d55695335f52d6fcf2b6a22ed45f5e4d99 (patch) | |
| tree | e17bfc8a9b55d5afbfe2f884322a96a54340f25d /src/gtk.rs | |
| parent | 31b60ae28e6aff6d23b378cd77e288c96c7db148 (diff) | |
Remote camera capability.
Diffstat (limited to 'src/gtk.rs')
| -rw-r--r-- | src/gtk.rs | 78 |
1 files changed, 59 insertions, 19 deletions
@@ -1,9 +1,11 @@ use anyhow::{anyhow, Result}; -use gtk4::{self as gtk, glib, cairo}; +use gtk4::{self as gtk, glib, cairo, gio}; use gtk4::prelude::*; use glib::{clone, spawn_future_local}; use std::thread; use std::sync::{Arc, Mutex}; +use std::rc::Rc; +use std::cell::RefCell; use crate::sync::Signal; use std::future::poll_fn; use std::task::Poll; @@ -49,12 +51,30 @@ pub struct Packet<T>{ pub image: cairo::ImageSurfaceDataOwned, pub attr: T, } -pub trait Overray: Send + 'static{} +pub trait Overlay: Send + 'static{ + type Widget: glib::object::IsA<gtk::Widget>; + fn empty() -> Result<Self::Widget>; + fn activate(_widget: &Self::Widget) -> Result<()>{ + Ok(()) + } + fn update(&self, _widget: &Self::Widget) -> Result<()>{ + Ok(()) + } +} pub trait Source: Send + 'static{ - type Attr: Overray; + type Attr: Overlay; fn next(&mut self, fbpool: impl FbSourceOnce) -> Result<Packet<Self::Attr>>; } -impl Overray for (){} +impl Overlay for (){ + type Widget = gtk::Box; + fn empty() -> Result<gtk::Box>{ + Ok(gtk::Box::builder() + .halign(gtk::Align::Start) + .valign(gtk::Align::Start) + .visible(false) + .build()) + } +} struct AppState<T>{ next: Mutex<Option<Packet<T>>>, @@ -63,7 +83,7 @@ struct AppState<T>{ fbpool: Mutex<FbPool>, } -fn sourcing_loop<Attr: Overray>( +fn sourcing_loop<Attr: Overlay>( apps: &AppState<Attr>, src: &mut impl Source<Attr=Attr> ) -> Result<()>{ @@ -81,23 +101,19 @@ fn sourcing_loop<Attr: Overray>( } } -fn activate<Attr: Overray>(app: >k::Application, apps: Arc<AppState<Attr>>){ +fn activate<Attr: Overlay>(app: >k::Application, apps: Arc<AppState<Attr>>){ let draw = gtk::DrawingArea::new(); - let mut frame_cache: Option<cairo::ImageSurface> = None; + let overlay = Attr::empty().unwrap(); + + let frame_cache: Rc<RefCell<Option<cairo::ImageSurface>>> + = Rc::new(RefCell::new(None)); draw.set_draw_func(clone!{ - #[strong] apps, + #[strong] frame_cache, move |_draw, ctx, canvas_w, canvas_h|{ ctx.set_source_rgb(0., 0., 0.); ctx.paint().unwrap(); - if let Some(newfb) = apps.next.lock().unwrap().take(){ - if let Some(lastframe) = frame_cache.take(){ - apps.fbpool.lock().unwrap() - .put(lastframe.take_data().unwrap()); - } - frame_cache = Some(newfb.image.into_inner()); - } - if let Some(image) = frame_cache.clone(){ + if let Some(image) = frame_cache.borrow_mut().clone(){ let ipat = cairo::SurfacePattern::create(&image); let scale = ((canvas_w as f64) / (image.width() as f64)).min( (canvas_h as f64) / (image.height() as f64)); @@ -110,10 +126,21 @@ fn activate<Attr: Overray>(app: >k::Application, apps: Arc<AppState<Attr>>){ spawn_future_local(poll_fn(clone!{ #[strong] apps, #[strong] draw, + #[strong] frame_cache, + #[strong] overlay, move |ctx|{ loop{ match apps.update.lock().unwrap().poll(ctx){ Poll::Ready(_) => { + if let Some(newfb) = apps.next.lock().unwrap().take(){ + let mut frame_cache = frame_cache.borrow_mut(); + if let Some(lastframe) = frame_cache.take(){ + apps.fbpool.lock().unwrap() + .put(lastframe.take_data().unwrap()); + } + *frame_cache = Some(newfb.image.into_inner()); + newfb.attr.update(&overlay).unwrap(); + } draw.queue_draw(); }, pending => return pending, @@ -136,11 +163,16 @@ fn activate<Attr: Overray>(app: >k::Application, apps: Arc<AppState<Attr>>){ } })); + let olcontainer = gtk::Overlay::builder() + .child(&draw) + .build(); + olcontainer.add_overlay(&overlay); let win = gtk::ApplicationWindow::builder() .application(app) - .child(&draw) + .child(&olcontainer) .build(); win.present(); + Attr::activate(&overlay).unwrap(); } pub fn main(src: impl Source + 'static) -> Result<glib::ExitCode>{ @@ -162,10 +194,18 @@ pub fn main(src: impl Source + 'static) -> Result<glib::ExitCode>{ }); let app = gtk::Application::builder() + .flags(gio::ApplicationFlags::HANDLES_COMMAND_LINE) .build(); - app.connect_activate(clone!{ + app.connect_command_line(clone!{ #[strong] apps, - move |app| activate(app, apps.clone()) + move |app, _| { + activate(app, apps.clone()); + 0 + } }); + //app.connect_activate(clone!{ + // #[strong] apps, + // move |app| activate(app, apps.clone()) + //}); Ok(app.run()) } |
