mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2025-04-01 20:14:13 +00:00
gtk: pass the scanout down to ConsoleArea
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
54f299599f
commit
d1e0ba0dde
@ -32,12 +32,12 @@ pub trait Console {
|
||||
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(Debug)]
|
||||
pub struct Console<'c> {
|
||||
pub struct Console {
|
||||
#[derivative(Debug = "ignore")]
|
||||
proxy: ConsoleProxy<'c>,
|
||||
proxy: ConsoleProxy<'static>,
|
||||
}
|
||||
|
||||
impl<'c> Console<'c> {
|
||||
impl Console {
|
||||
pub fn new(conn: &zbus::Connection, idx: u32) -> Result<Self> {
|
||||
let proxy = ConsoleProxy::new_for_owned_path(
|
||||
conn.clone(),
|
||||
@ -89,7 +89,7 @@ impl<'c> Console<'c> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "glib")]
|
||||
impl<'c> Console<'c> {
|
||||
impl Console {
|
||||
pub fn glib_listen(&self) -> Result<glib::Receiver<Event>> {
|
||||
let (p0, p1) = UnixStream::pair()?;
|
||||
let (tx, rx) = glib::MainContext::channel(glib::source::Priority::default());
|
||||
|
@ -2,9 +2,29 @@ use std::cell::RefCell;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::{SendError, Sender};
|
||||
use std::ops::Drop;
|
||||
|
||||
use zbus::{dbus_interface, export::zvariant::Fd};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Scanout {
|
||||
fd: RawFd,
|
||||
width: u32,
|
||||
height: u32,
|
||||
stride: u32,
|
||||
fourcc: u32,
|
||||
modifier: u64,
|
||||
y0_top: bool,
|
||||
}
|
||||
|
||||
impl Drop for Scanout {
|
||||
fn drop(&mut self) {
|
||||
if self.fd >= 0 {
|
||||
unsafe { libc::close(self.fd); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: replace events mpsc with async traits
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
@ -18,15 +38,6 @@ pub enum Event {
|
||||
w: i32,
|
||||
h: i32,
|
||||
},
|
||||
Scanout {
|
||||
fd: RawFd,
|
||||
width: u32,
|
||||
height: u32,
|
||||
stride: u32,
|
||||
fourcc: u32,
|
||||
modifier: u64,
|
||||
y0_top: bool,
|
||||
},
|
||||
MouseSet {
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -39,6 +50,7 @@ pub enum Event {
|
||||
hot_y: i32,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
Scanout(Scanout),
|
||||
}
|
||||
|
||||
pub(crate) trait EventSender {
|
||||
@ -85,7 +97,7 @@ impl<E: 'static + EventSender> Listener<E> {
|
||||
y0_top: bool,
|
||||
) {
|
||||
let fd = unsafe { libc::dup(fd.as_raw_fd()) };
|
||||
self.send(Event::Scanout {
|
||||
self.send(Event::Scanout(Scanout {
|
||||
fd,
|
||||
width,
|
||||
height,
|
||||
@ -93,7 +105,7 @@ impl<E: 'static + EventSender> Listener<E> {
|
||||
fourcc,
|
||||
modifier,
|
||||
y0_top,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn mouse_set(&mut self, x: i32, y: i32, on: i32) {
|
||||
|
@ -7,7 +7,7 @@
|
||||
<child>
|
||||
<object class="GtkNotebook">
|
||||
<child>
|
||||
<object class="GtkGLArea" id="glarea"/>
|
||||
<object class="QemuConsoleArea" id="area"/>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="notebook-tab">
|
||||
|
@ -1,18 +1,25 @@
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk::subclass::widget::WidgetImplExt;
|
||||
use gtk::{gio, glib, CompositeTemplate};
|
||||
use gtk::{glib, CompositeTemplate};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
use qemu_display_listener::{Console, Event};
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::subclass;
|
||||
use gtk::subclass::prelude::*;
|
||||
|
||||
#[derive(Debug, CompositeTemplate)]
|
||||
#[derive(Debug, CompositeTemplate, Default)]
|
||||
#[template(resource = "/org/qemu/gtk4/console.ui")]
|
||||
pub struct QemuConsole {
|
||||
#[template_child]
|
||||
pub area: TemplateChild<crate::console_area::QemuConsoleArea>,
|
||||
#[template_child]
|
||||
pub label: TemplateChild<gtk::Label>,
|
||||
pub console: OnceCell<Console>,
|
||||
}
|
||||
|
||||
impl ObjectSubclass for QemuConsole {
|
||||
@ -26,9 +33,7 @@ mod imp {
|
||||
glib::object_subclass!();
|
||||
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
label: TemplateChild::default(),
|
||||
}
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
@ -65,3 +70,27 @@ mod imp {
|
||||
glib::wrapper! {
|
||||
pub struct QemuConsole(ObjectSubclass<imp::QemuConsole>) @extends gtk::Widget;
|
||||
}
|
||||
|
||||
impl QemuConsole {
|
||||
pub fn set_qemu_console(&self, console: Console) {
|
||||
let priv_ = imp::QemuConsole::from_instance(self);
|
||||
let rx = console
|
||||
.glib_listen()
|
||||
.expect("Failed to listen to the console");
|
||||
rx.attach(
|
||||
None,
|
||||
clone!(@weak self as con => move |t| {
|
||||
let con = imp::QemuConsole::from_instance(&con);
|
||||
match t {
|
||||
Event::Scanout(s) => {
|
||||
con.label.set_label(&format!("{:?}", s));
|
||||
con.area.set_scanout(s);
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
Continue(true)
|
||||
}),
|
||||
);
|
||||
priv_.console.set(console).unwrap();
|
||||
}
|
||||
}
|
||||
|
72
qemu-gtk4/src/console_area.rs
Normal file
72
qemu-gtk4/src/console_area.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use std::cell::Cell;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk::{glib, graphene, gdk};
|
||||
|
||||
use qemu_display_listener::Scanout;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::subclass;
|
||||
use gtk::subclass::prelude::*;
|
||||
|
||||
pub struct QemuConsoleArea {
|
||||
pub scanout: Cell<Option<Scanout>>,
|
||||
}
|
||||
|
||||
impl ObjectSubclass for QemuConsoleArea {
|
||||
const NAME: &'static str = "QemuConsoleArea";
|
||||
type Type = super::QemuConsoleArea;
|
||||
type ParentType = gtk::Widget;
|
||||
type Interfaces = ();
|
||||
type Instance = subclass::simple::InstanceStruct<Self>;
|
||||
type Class = subclass::simple::ClassStruct<Self>;
|
||||
|
||||
glib::object_subclass!();
|
||||
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
scanout: Cell::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for QemuConsoleArea {
|
||||
fn constructed(&self, obj: &Self::Type) {
|
||||
self.parent_constructed(obj);
|
||||
|
||||
let ec = gtk::EventControllerLegacy::new();
|
||||
// XXX: where are the key events?
|
||||
// ec.set_propagation_phase(gtk::PropagationPhase::Bubble);
|
||||
obj.add_controller(&ec);
|
||||
ec.connect_event(clone!(@weak obj => move |_, e| {
|
||||
dbg!(e);
|
||||
true
|
||||
}));
|
||||
obj.set_focusable(true);
|
||||
obj.set_focus_on_click(true);
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for QemuConsoleArea {
|
||||
fn snapshot(&self, widget: &Self::Type, snapshot: >k::Snapshot) {
|
||||
let (width, height) = (widget.get_width() as f32, widget.get_height() as f32);
|
||||
let whole = &graphene::Rect::new(0_f32, 0_f32, width, height);
|
||||
// TODO: make this a CSS style?
|
||||
snapshot.append_color(&gdk::RGBA::black(), whole);
|
||||
//snapshot.append_texture(priv_.texture, whole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct QemuConsoleArea(ObjectSubclass<imp::QemuConsoleArea>) @extends gtk::Widget;
|
||||
}
|
||||
|
||||
impl QemuConsoleArea {
|
||||
pub fn set_scanout(&self, s: Scanout) {
|
||||
let priv_ = imp::QemuConsoleArea::from_instance(self);
|
||||
priv_.scanout.replace(Some(s));
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ mod application;
|
||||
mod config;
|
||||
mod window;
|
||||
mod console;
|
||||
mod console_area;
|
||||
|
||||
use application::QemuApplication;
|
||||
use config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};
|
||||
|
@ -21,6 +21,8 @@ run_command(
|
||||
sources = files(
|
||||
'application.rs',
|
||||
'config.rs',
|
||||
'console.rs',
|
||||
'console_area.rs',
|
||||
'main.rs',
|
||||
'window.rs',
|
||||
)
|
||||
|
@ -1,14 +1,13 @@
|
||||
use crate::application::QemuApplication;
|
||||
use crate::console::QemuConsole;
|
||||
use crate::config::{APP_ID, PROFILE};
|
||||
use glib::clone;
|
||||
use glib::signal::Inhibit;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{self, prelude::*};
|
||||
use gtk::{gio, glib, CompositeTemplate};
|
||||
use log::warn;
|
||||
|
||||
use qemu_display_listener::{Console as ConsoleListener, Event};
|
||||
use qemu_display_listener::Console;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
@ -21,10 +20,6 @@ mod imp {
|
||||
pub headerbar: TemplateChild<gtk::HeaderBar>,
|
||||
#[template_child]
|
||||
pub console: TemplateChild<QemuConsole>,
|
||||
// #[template_child]
|
||||
// pub glarea: TemplateChild<gtk::GLArea>,
|
||||
// #[template_child]
|
||||
// pub label: TemplateChild<gtk::Label>,
|
||||
pub settings: gio::Settings,
|
||||
}
|
||||
|
||||
@ -42,8 +37,6 @@ mod imp {
|
||||
Self {
|
||||
headerbar: TemplateChild::default(),
|
||||
console: TemplateChild::default(),
|
||||
// label: TemplateChild::default(),
|
||||
// glarea: TemplateChild::default(),
|
||||
settings: gio::Settings::new(APP_ID),
|
||||
}
|
||||
}
|
||||
@ -96,37 +89,15 @@ glib::wrapper! {
|
||||
}
|
||||
|
||||
impl QemuApplicationWindow {
|
||||
pub fn new(app: &QemuApplication, console: ConsoleListener) -> Self {
|
||||
pub fn new(app: &QemuApplication, console: Console) -> Self {
|
||||
let window: Self = glib::Object::new(&[]).expect("Failed to create QemuApplicationWindow");
|
||||
window.set_application(Some(app));
|
||||
|
||||
let win = &imp::QemuApplicationWindow::from_instance(&window);
|
||||
// win.glarea.connect_render(clone!(@weak window as win => move |area, ctxt| {
|
||||
// dbg!("render");
|
||||
// Inhibit(false)
|
||||
// }));
|
||||
|
||||
win.console.set_qemu_console(console);
|
||||
// Set icons for shell
|
||||
gtk::Window::set_default_icon_name(APP_ID);
|
||||
|
||||
let rx = console
|
||||
.glib_listen()
|
||||
.expect("Failed to listen to the console");
|
||||
rx.attach(
|
||||
None,
|
||||
clone!(@weak window as win => move |t| {
|
||||
let win = &imp::QemuApplicationWindow::from_instance(&win);
|
||||
match t {
|
||||
Event::Scanout { .. } => {
|
||||
// win.label.set_text(&format!("{:?}", t));
|
||||
// win.glarea.queue_render();
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
Continue(true)
|
||||
}),
|
||||
);
|
||||
|
||||
window
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user