Protocol names #41

Merged
mars merged 7 commits from protocol-names into main 2022-11-17 02:29:39 +00:00
13 changed files with 107 additions and 72 deletions

View File

@ -24,6 +24,7 @@ pub type PanelId = u32;
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CreatePanel { pub struct CreatePanel {
pub id: PanelId, pub id: PanelId,
pub protocol: String,
pub script: PathBuf, pub script: PathBuf,
} }

View File

@ -99,7 +99,11 @@ impl Client {
while let Some(msg) = self.messenger.recv() { while let Some(msg) = self.messenger.recv() {
println!("Client #{}: {:?}", self.token.0, msg); println!("Client #{}: {:?}", self.token.0, msg);
match msg { match msg {
MagpieServerMsg::CreatePanel(CreatePanel { id, script }) => { MagpieServerMsg::CreatePanel(CreatePanel {
id,
protocol,
script,
}) => {
let window = self.data.write().new_window_id(); let window = self.data.write().new_window_id();
if let Some(old_id) = self.id_to_window.insert(id, window) { if let Some(old_id) = self.id_to_window.insert(id, window) {
@ -107,7 +111,11 @@ impl Client {
let _ = self.window_sender.send_event(msg); let _ = self.window_sender.send_event(msg);
} }
let msg = WindowMessage::OpenWindow { id: window, script }; let msg = WindowMessage::OpenWindow {
id: window,
protocol,
script,
};
let _ = self.window_sender.send_event(msg); let _ = self.window_sender.send_event(msg);
} }
MagpieServerMsg::SendMessage(SendMessage { id, msg }) => { MagpieServerMsg::SendMessage(SendMessage { id, msg }) => {

View File

@ -17,10 +17,19 @@ use crate::service::ipc::{IpcMessage, IpcMessageSender};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum WindowMessage { pub enum WindowMessage {
OpenWindow { id: usize, script: PathBuf }, OpenWindow {
CloseWindow { id: usize }, id: usize,
protocol: String,
script: PathBuf,
},
CloseWindow {
id: usize,
},
Quit, Quit,
SendMessage { id: usize, msg: Vec<u8> }, SendMessage {
id: usize,
msg: Vec<u8>,
},
} }
pub type WindowMessageSender = EventLoopProxy<WindowMessage>; pub type WindowMessageSender = EventLoopProxy<WindowMessage>;
@ -155,11 +164,11 @@ impl WindowStore {
message: WindowMessage, message: WindowMessage,
) -> anyhow::Result<bool> { ) -> anyhow::Result<bool> {
match message { match message {
WindowMessage::OpenWindow { id, script } => { WindowMessage::OpenWindow { id, protocol, script } => {
println!("Opening window {} with script {:?}", id, script); println!("Opening window {} with script {:?}", id, script);
let module = std::fs::read(script)?; let module = std::fs::read(script)?;
let mut script = self.runtime.load_module(&module)?; let mut script = self.runtime.load_module(&module)?;
let panel = script.create_panel(vec![])?; let panel = script.create_panel(&protocol, vec![])?;
let window = Window::new(panel, &event_loop)?; let window = Window::new(panel, &event_loop)?;
let window_id = window.get_id(); let window_id = window.get_id();
self.windows.insert(window_id, window); self.windows.insert(window_id, window);

View File

@ -86,8 +86,9 @@ fn main() {
let player_finder = PlayerFinder::new().expect("Could not connect to D-Bus"); let player_finder = PlayerFinder::new().expect("Could not connect to D-Bus");
let mut magpie = MagpieClient::new().unwrap(); let mut magpie = MagpieClient::new().unwrap();
let protocol = "tebibyte-media.desktop.music-player-controller".to_string();
let script = std::path::PathBuf::from(&module_path); let script = std::path::PathBuf::from(&module_path);
let msg = CreatePanel { id: 0, script }; let msg = CreatePanel { id: 0, protocol, script };
let msg = MagpieServerMsg::CreatePanel(msg); let msg = MagpieServerMsg::CreatePanel(msg);
magpie.messenger.send(&msg).unwrap(); magpie.messenger.send(&msg).unwrap();

View File

@ -31,6 +31,7 @@ struct App {
panels: Vec<PanelWindow>, panels: Vec<PanelWindow>,
next_idx: usize, next_idx: usize,
last_update: Instant, last_update: Instant,
protocol_buf: String,
bind_message_buf: String, bind_message_buf: String,
} }
@ -46,6 +47,7 @@ impl App {
panels: vec![], panels: vec![],
next_idx: 0, next_idx: 0,
last_update: Instant::now(), last_update: Instant::now(),
protocol_buf: String::new(),
bind_message_buf: String::new(), bind_message_buf: String::new(),
} }
} }
@ -56,12 +58,16 @@ impl eframe::App for App {
ctx.request_repaint(); ctx.request_repaint();
egui::SidePanel::left("left_panel").show(ctx, |ui| { egui::SidePanel::left("left_panel").show(ctx, |ui| {
ui.label("Protocol name:");
ui.text_edit_singleline(&mut self.protocol_buf);
ui.label("Bind message:");
let text_edit = egui::TextEdit::multiline(&mut self.bind_message_buf).code_editor(); let text_edit = egui::TextEdit::multiline(&mut self.bind_message_buf).code_editor();
ui.add(text_edit); ui.add(text_edit);
if ui.button("Bind Panel").clicked() { if ui.button("Bind Panel").clicked() {
let msg = self.bind_message_buf.as_bytes().to_vec(); let msg = self.bind_message_buf.as_bytes().to_vec();
let panel = self.script.create_panel(msg).unwrap(); let panel = self.script.create_panel(&self.protocol_buf, msg).unwrap();
let index = self.next_idx; let index = self.next_idx;
self.next_idx += 1; self.next_idx += 1;

View File

@ -7,11 +7,17 @@ use super::*;
static mut PANEL_IMPLS: Vec<Box<dyn PanelImpl>> = Vec::new(); static mut PANEL_IMPLS: Vec<Box<dyn PanelImpl>> = Vec::new();
pub fn bind_panel<T: BindPanel>(panel: u32, msg: u32) -> u32 { pub fn bind_panel(
cb: impl Fn(Panel, Message, Message) -> Box<dyn PanelImpl>,
panel: u32,
protocol: u32,
msg: u32,
) -> u32 {
unsafe { unsafe {
let panel = Panel(panel); let panel = Panel(panel);
let protocol = Message(protocol);
let msg = Message(msg); let msg = Message(msg);
let panel_impl = T::bind(panel, msg); let panel_impl = cb(panel, protocol, msg);
let id = PANEL_IMPLS.len() as u32; let id = PANEL_IMPLS.len() as u32;
PANEL_IMPLS.push(panel_impl); PANEL_IMPLS.push(panel_impl);
id id

View File

@ -9,10 +9,10 @@ pub mod abi;
#[macro_export] #[macro_export]
macro_rules! export_abi { macro_rules! export_abi {
($panel_impl: ident) => { ($bind_panel: ident) => {
#[no_mangle] #[no_mangle]
pub extern "C" fn bind_panel(panel: u32, msg: u32) -> u32 { pub extern "C" fn bind_panel(panel: u32, protocol: u32, msg: u32) -> u32 {
::canary_script::api::abi::bind_panel::<$panel_impl>(panel, msg) ::canary_script::api::abi::bind_panel($bind_panel, panel, protocol, msg)
} }
#[no_mangle] #[no_mangle]
@ -42,10 +42,6 @@ macro_rules! export_abi {
}; };
} }
pub trait BindPanel {
fn bind(panel: Panel, msg: Message) -> Box<dyn PanelImpl>;
}
pub trait PanelImpl { pub trait PanelImpl {
fn update(&mut self, dt: f32); fn update(&mut self, dt: f32);
fn draw(&mut self); fn draw(&mut self);
@ -375,7 +371,6 @@ impl DrawContext {
self.draw_rect(bottom_edge, color); self.draw_rect(bottom_edge, color);
} }
self.draw_rect(inner_rect, color); self.draw_rect(inner_rect, color);
} }

View File

@ -4,10 +4,14 @@
#[global_allocator] #[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
use canary_script::*;
use api::*; use api::*;
use canary_script::*;
canary_script::export_abi!(MusicPlayerPanel); canary_script::export_abi!(bind_panel_impl);
pub fn bind_panel_impl(panel: Panel, _protocol: Message, message: Message) -> Box<dyn PanelImpl> {
MusicPlayerPanel::bind(panel, message)
}
const DISPLAY_FONT: &str = "Liberation Sans"; const DISPLAY_FONT: &str = "Liberation Sans";
@ -17,19 +21,6 @@ pub struct MusicPlayerPanel {
label: Label, label: Label,
} }
impl BindPanel for MusicPlayerPanel {
fn bind(panel: Panel, message: Message) -> Box<dyn PanelImpl> {
let display_font = Font::new(DISPLAY_FONT);
let label = Label::new(display_font, "Hello, world!".into(), 1.2);
let panel = Self {
panel,
display_font,
label,
};
Box::new(panel)
}
}
impl PanelImpl for MusicPlayerPanel { impl PanelImpl for MusicPlayerPanel {
fn update(&mut self, dt: f32) {} fn update(&mut self, dt: f32) {}
@ -42,20 +33,31 @@ impl PanelImpl for MusicPlayerPanel {
self.label.draw(&ctx, offset, size, color); self.label.draw(&ctx, offset, size, color);
} }
fn on_resize(&mut self, new_size: Vec2) { fn on_resize(&mut self, new_size: Vec2) {}
}
fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {} fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {}
fn on_message(&mut self, msg: Message) { fn on_message(&mut self, msg: Message) {
use canary_music_player::{InMsg, serde_json}; use canary_music_player::{serde_json, InMsg};
let msg = msg.to_vec(); let msg = msg.to_vec();
let msg = serde_json::from_slice::<InMsg>(&msg); let msg = serde_json::from_slice::<InMsg>(&msg);
self.label.set_text(format!("{:#?}", msg)); self.label.set_text(format!("{:#?}", msg));
} }
} }
impl MusicPlayerPanel {
pub fn bind(panel: Panel, _message: Message) -> Box<dyn PanelImpl> {
let display_font = Font::new(DISPLAY_FONT);
let label = Label::new(display_font, "Hello, world!".into(), 1.2);
let panel = Self {
panel,
display_font,
label,
};
Box::new(panel)
}
}
pub struct Label { pub struct Label {
font: Font, font: Font,
text: String, text: String,

View File

@ -8,12 +8,16 @@ pub mod anim;
pub mod main_menu; pub mod main_menu;
pub mod widgets; pub mod widgets;
use canary_script::*;
use api::*; use api::*;
use widgets::Widget; use canary_script::*;
use main_menu::MainMenuPanel; use main_menu::MainMenuPanel;
use widgets::Widget;
export_abi!(MainMenuPanel); export_abi!(bind_panel_impl);
fn bind_panel_impl(panel: Panel, _protocol: Message, msg: Message) -> Box<dyn PanelImpl> {
MainMenuPanel::bind(panel, msg)
}
pub const ICON_FONT: &str = "Iosevka Nerd Font"; pub const ICON_FONT: &str = "Iosevka Nerd Font";
pub const DISPLAY_FONT: &str = "Homenaje"; pub const DISPLAY_FONT: &str = "Homenaje";
@ -24,18 +28,6 @@ pub struct ConfirmationDialogPanel {
dialog: widgets::dialog::Dialog, dialog: widgets::dialog::Dialog,
} }
impl BindPanel for ConfirmationDialogPanel {
fn bind(panel: Panel, msg: Message) -> Box<dyn PanelImpl> {
let msg = msg.to_vec();
let info: DialogInfo = serde_json::from_slice(&msg).unwrap();
use widgets::dialog::*;
let style = DialogStyle::default();
let dialog = Dialog::new(style, &info);
Box::new(Self { panel, dialog })
}
}
impl PanelImpl for ConfirmationDialogPanel { impl PanelImpl for ConfirmationDialogPanel {
fn update(&mut self, dt: f32) { fn update(&mut self, dt: f32) {
self.dialog.update(dt); self.dialog.update(dt);
@ -54,3 +46,15 @@ impl PanelImpl for ConfirmationDialogPanel {
fn on_message(&mut self, _msg: Message) {} fn on_message(&mut self, _msg: Message) {}
} }
impl ConfirmationDialogPanel {
pub fn bind(panel: Panel, msg: Message) -> Box<dyn PanelImpl> {
let msg = msg.to_vec();
let info: DialogInfo = serde_json::from_slice(&msg).unwrap();
use widgets::dialog::*;
let style = DialogStyle::default();
let dialog = Dialog::new(style, &info);
Box::new(Self { panel, dialog })
}
}

View File

@ -15,15 +15,6 @@ pub struct MainMenuPanel {
menu: MainMenu, menu: MainMenu,
} }
impl BindPanel for MainMenuPanel {
fn bind(panel: Panel, msg: Message) -> Box<dyn PanelImpl> {
Box::new(Self {
panel,
menu: MainMenu::default(),
})
}
}
impl PanelImpl for MainMenuPanel { impl PanelImpl for MainMenuPanel {
fn update(&mut self, dt: f32) { fn update(&mut self, dt: f32) {
Widget::update(&mut self.menu, dt); Widget::update(&mut self.menu, dt);
@ -43,6 +34,15 @@ impl PanelImpl for MainMenuPanel {
fn on_message(&mut self, msg: Message) {} fn on_message(&mut self, msg: Message) {}
} }
impl MainMenuPanel {
pub fn bind(panel: Panel, msg: Message) -> Box<dyn PanelImpl> {
Box::new(Self {
panel,
menu: MainMenu::default(),
})
}
}
pub struct MainMenu { pub struct MainMenu {
pub menu: Offset<SlotMenu<RoundButton>>, pub menu: Offset<SlotMenu<RoundButton>>,
pub player_info: Reveal<Offset<PlayerInfo>>, pub player_info: Reveal<Offset<PlayerInfo>>,

View File

@ -36,10 +36,11 @@ pub trait Instance {
/// Binds script data to a Canary panel. /// Binds script data to a Canary panel.
/// ///
/// To "bind" a Canary panel to a Canary script, this function must be /// To "bind" a Canary panel to a Canary script, this function must be
/// called. It passes the ID of a panel to the script, plus an /// called. It passes the ID of a panel to the script, the name of the
/// initialization message, and the script returns an integer as /// protocol that this panel will be using, plus an initialization
/// userdata. All panel events will be identified to the script with this /// message, and the script returns an integer as userdata. All panel
/// userdata as the first argument. /// events will be identified to the script with this userdata as the first
/// argument.
/// ///
/// The intended usecase for this userdata is to contain a pointer. A /// The intended usecase for this userdata is to contain a pointer. A
/// Canary script can allocate some high-level object in memory, and when /// Canary script can allocate some high-level object in memory, and when
@ -47,7 +48,7 @@ pub trait Instance {
/// userdata. Then, when the runtime calls back into the script, the /// userdata. Then, when the runtime calls back into the script, the
/// userdata will be reinterpreted as a pointer and a method can be called /// userdata will be reinterpreted as a pointer and a method can be called
/// on that object in memory. /// on that object in memory.
fn bind_panel(&self, panel: PanelId, msg: Vec<u8>) -> u32; fn bind_panel(&self, panel: PanelId, protocol: &str, msg: Vec<u8>) -> u32;
fn update(&self, panel_ud: u32, dt: f32); fn update(&self, panel_ud: u32, dt: f32);

View File

@ -61,7 +61,7 @@ impl Backend for WasmtimeBackend {
pub struct WasmtimeInstance { pub struct WasmtimeInstance {
store: Mutex<Store>, store: Mutex<Store>,
bind_panel: wasmtime::TypedFunc<(u32, u32), u32>, bind_panel: wasmtime::TypedFunc<(u32, u32, u32), u32>,
update: wasmtime::TypedFunc<(u32, f32), ()>, update: wasmtime::TypedFunc<(u32, f32), ()>,
draw: wasmtime::TypedFunc<u32, ()>, draw: wasmtime::TypedFunc<u32, ()>,
on_resize: wasmtime::TypedFunc<(u32, f32, f32), ()>, on_resize: wasmtime::TypedFunc<(u32, f32, f32), ()>,
@ -189,11 +189,13 @@ impl WasmtimeInstance {
} }
impl Instance for WasmtimeInstance { impl Instance for WasmtimeInstance {
fn bind_panel(&self, panel: PanelId, msg: Vec<u8>) -> u32 { fn bind_panel(&self, panel: PanelId, protocol: &str, msg: Vec<u8>) -> u32 {
let mut store = self.store.lock(); let mut store = self.store.lock();
let protocol = store.data().message_new(protocol.as_bytes().to_vec());
let msg = store.data().message_new(msg); let msg = store.data().message_new(msg);
let args = (panel.0 as u32, msg); let args = (panel.0 as u32, protocol, msg);
let data = self.bind_panel.call(store.deref_mut(), args).unwrap(); let data = self.bind_panel.call(store.deref_mut(), args).unwrap();
store.data().message_free(protocol);
store.data().message_free(msg); store.data().message_free(msg);
data data
} }

View File

@ -45,10 +45,10 @@ pub struct Script {
} }
impl Script { impl Script {
pub fn create_panel(&mut self, msg: Vec<u8>) -> anyhow::Result<Panel> { pub fn create_panel(&mut self, protocol: &str, msg: Vec<u8>) -> anyhow::Result<Panel> {
let id = PanelId(self.next_panel); let id = PanelId(self.next_panel);
self.next_panel += 1; self.next_panel += 1;
let userdata = self.instance.bind_panel(id, msg); let userdata = self.instance.bind_panel(id, protocol, msg);
Ok(Panel { Ok(Panel {
instance: self.instance.clone(), instance: self.instance.clone(),
id, id,