wip; sending window close events back to elixir is pretty slick.
This commit is contained in:
parent
244dedfb9b
commit
fc46908151
|
@ -114,4 +114,39 @@ defmodule Scenic.Driver.Renderling.Window do
|
|||
def terminate(_, driver) do
|
||||
Nif.terminate(driver.assigns.server)
|
||||
end
|
||||
|
||||
@doc false
|
||||
@impl GenServer
|
||||
|
||||
def handle_info(:shutdown, driver) do
|
||||
case driver.assigns.config.on_close do
|
||||
:restart ->
|
||||
{:stop, :normal, driver}
|
||||
|
||||
:stop_driver ->
|
||||
ViewPort.stop_driver(driver.viewport, self())
|
||||
{:stop, :normal, driver}
|
||||
|
||||
:stop_viewport ->
|
||||
ViewPort.stop(driver.viewport)
|
||||
{:stop, :normal, driver}
|
||||
|
||||
:stop_system ->
|
||||
System.stop(:shutdown)
|
||||
{:stop, :normal, driver}
|
||||
|
||||
:halt_system ->
|
||||
System.halt(:shutdown)
|
||||
{:stop, :normal, driver}
|
||||
|
||||
{module, _fun, 1} ->
|
||||
module.fun(:shutdown)
|
||||
{:stop, :normal, driver}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_info(msg, driver) do
|
||||
dbg(msg)
|
||||
{:noreply, driver}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::message;
|
||||
use rustler::{NifStruct, NifTaggedEnum, NifTuple, NifUnitEnum, NifUntaggedEnum, Term};
|
||||
|
||||
/// Structures received from BEAM.
|
||||
|
@ -405,3 +406,111 @@ pub enum InputClass {
|
|||
Led,
|
||||
Switch,
|
||||
}
|
||||
|
||||
#[derive(NifTuple, Debug, Clone)]
|
||||
pub struct Point(u32, u32);
|
||||
|
||||
impl From<message::Point> for Point {
|
||||
fn from(point: message::Point) -> Self {
|
||||
Point(point.x, point.y)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(NifUnitEnum, Debug, Clone)]
|
||||
pub enum ModifierKey {
|
||||
Meta,
|
||||
Alt,
|
||||
Ctrl,
|
||||
Shift,
|
||||
CapsLock,
|
||||
NumLock,
|
||||
ScrollLock,
|
||||
}
|
||||
|
||||
impl From<message::ModifierKey> for ModifierKey {
|
||||
fn from(key: message::ModifierKey) -> Self {
|
||||
match key {
|
||||
message::ModifierKey::Meta => ModifierKey::Meta,
|
||||
message::ModifierKey::Alt => ModifierKey::Alt,
|
||||
message::ModifierKey::Ctrl => ModifierKey::Ctrl,
|
||||
message::ModifierKey::Shift => ModifierKey::Shift,
|
||||
message::ModifierKey::CapsLock => ModifierKey::CapsLock,
|
||||
message::ModifierKey::NumLock => ModifierKey::NumLock,
|
||||
message::ModifierKey::ScrollLock => ModifierKey::ScrollLock,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(NifUnitEnum, Debug, Clone)]
|
||||
pub enum ViewPortEvent {
|
||||
Enter,
|
||||
Exit,
|
||||
Reshape,
|
||||
}
|
||||
|
||||
impl From<message::ViewPortEvent> for ViewPortEvent {
|
||||
fn from(event: message::ViewPortEvent) -> Self {
|
||||
match event {
|
||||
message::ViewPortEvent::Enter => ViewPortEvent::Enter,
|
||||
message::ViewPortEvent::Exit => ViewPortEvent::Exit,
|
||||
message::ViewPortEvent::Reshape => ViewPortEvent::Reshape,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(NifTaggedEnum, Debug, Clone)]
|
||||
pub enum InputEvent {
|
||||
CodePoint(String, Vec<ModifierKey>),
|
||||
Key(String, u8, Vec<ModifierKey>),
|
||||
CursorButton(String, u8, Vec<ModifierKey>, Point),
|
||||
CursorScroll(Point, Point),
|
||||
CursorPos(Point),
|
||||
ViewPort(ViewPortEvent, Point),
|
||||
Relative(Point),
|
||||
Led(String, u32),
|
||||
Switch(String, u32),
|
||||
}
|
||||
|
||||
impl From<message::InputEvent> for InputEvent {
|
||||
fn from(event: message::InputEvent) -> Self {
|
||||
match event {
|
||||
message::InputEvent::CodePoint {
|
||||
codepoint,
|
||||
modifiers,
|
||||
} => InputEvent::CodePoint(
|
||||
codepoint,
|
||||
modifiers.iter().map(|x| x.clone().into()).collect(),
|
||||
),
|
||||
message::InputEvent::Key {
|
||||
key,
|
||||
value,
|
||||
modifiers,
|
||||
} => InputEvent::Key(
|
||||
key,
|
||||
value,
|
||||
modifiers.iter().map(|x| x.clone().into()).collect(),
|
||||
),
|
||||
message::InputEvent::CursorButton {
|
||||
button,
|
||||
value,
|
||||
modifiers,
|
||||
position,
|
||||
} => InputEvent::CursorButton(
|
||||
button,
|
||||
value,
|
||||
modifiers.iter().map(|x| x.clone().into()).collect(),
|
||||
position.into(),
|
||||
),
|
||||
message::InputEvent::CursorScroll { offset, position } => {
|
||||
InputEvent::CursorScroll(offset.into(), position.into())
|
||||
}
|
||||
message::InputEvent::CursorPos { position } => InputEvent::CursorPos(position.into()),
|
||||
message::InputEvent::ViewPort { event, position } => {
|
||||
InputEvent::ViewPort(event.into(), position.into())
|
||||
}
|
||||
message::InputEvent::Relative { position } => InputEvent::Relative(position.into()),
|
||||
message::InputEvent::Led { id, value } => InputEvent::Led(id, value),
|
||||
message::InputEvent::Switch { id, value } => InputEvent::Switch(id, value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
mod elixir_types;
|
||||
mod message;
|
||||
|
||||
use crate::elixir_types::{Color, DriverConfig, InputClass, ScriptItem};
|
||||
use crate::elixir_types::{Color, DriverConfig, InputClass, InputEvent, ScriptItem};
|
||||
use ipc_channel::ipc::{IpcOneShotServer, IpcReceiver, IpcSender};
|
||||
use rustler::{Env, NifResult, ResourceArc, Term};
|
||||
use rustler::{Encoder, Env, LocalPid, NifResult, OwnedEnv, ResourceArc, Term};
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::sync::Mutex;
|
||||
use std::thread::sleep;
|
||||
|
||||
struct IpcResourceInner {
|
||||
ipc_channel_name: String,
|
||||
sender: IpcSender<message::Message>,
|
||||
receiver: IpcReceiver<message::Message>,
|
||||
handle: Child,
|
||||
}
|
||||
|
||||
struct IpcResource(Mutex<IpcResourceInner>);
|
||||
|
||||
#[rustler::nif]
|
||||
fn init(cfg: DriverConfig) -> ResourceArc<IpcResource> {
|
||||
fn init(env: Env<'_>, cfg: DriverConfig) -> ResourceArc<IpcResource> {
|
||||
let (ipc, ipc_channel_name) = IpcOneShotServer::<message::IpcExchange>::new().unwrap();
|
||||
|
||||
let handle = Command::new(cfg.server_path.clone())
|
||||
|
@ -32,12 +30,28 @@ fn init(cfg: DriverConfig) -> ResourceArc<IpcResource> {
|
|||
|
||||
sender.send(cfg.into()).unwrap();
|
||||
|
||||
ResourceArc::new(IpcResource(Mutex::new(IpcResourceInner {
|
||||
ipc_channel_name,
|
||||
handle,
|
||||
sender,
|
||||
receiver,
|
||||
})))
|
||||
let pid = env.pid();
|
||||
|
||||
std::thread::spawn(move || loop {
|
||||
let event = receiver.recv().unwrap();
|
||||
let mut msg_env = OwnedEnv::new();
|
||||
match event {
|
||||
message::Message::InputEvent(input_event) => {
|
||||
let _ = msg_env.send_and_clear(&pid, |env| {
|
||||
let input_event: InputEvent = input_event.into();
|
||||
input_event.encode(env)
|
||||
});
|
||||
}
|
||||
message::Message::Shutdown => {
|
||||
let _ = msg_env.send_and_clear(&pid, |env| {
|
||||
rustler::Atom::from_str(env, "shutdown").unwrap()
|
||||
});
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
});
|
||||
|
||||
ResourceArc::new(IpcResource(Mutex::new(IpcResourceInner { handle, sender })))
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
|
|
|
@ -611,6 +611,71 @@ impl From<elixir_types::ScriptItem> for ScriptItem {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum ModifierKey {
|
||||
Meta,
|
||||
Alt,
|
||||
Ctrl,
|
||||
Shift,
|
||||
CapsLock,
|
||||
NumLock,
|
||||
ScrollLock,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Point {
|
||||
pub x: u32,
|
||||
pub y: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum ViewPortEvent {
|
||||
Enter,
|
||||
Exit,
|
||||
Reshape,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum InputEvent {
|
||||
CodePoint {
|
||||
codepoint: String,
|
||||
modifiers: Vec<ModifierKey>,
|
||||
},
|
||||
Key {
|
||||
key: String,
|
||||
value: u8,
|
||||
modifiers: Vec<ModifierKey>,
|
||||
},
|
||||
CursorButton {
|
||||
button: String,
|
||||
value: u8,
|
||||
modifiers: Vec<ModifierKey>,
|
||||
position: Point,
|
||||
},
|
||||
CursorScroll {
|
||||
offset: Point,
|
||||
position: Point,
|
||||
},
|
||||
CursorPos {
|
||||
position: Point,
|
||||
},
|
||||
ViewPort {
|
||||
event: ViewPortEvent,
|
||||
position: Point,
|
||||
},
|
||||
Relative {
|
||||
position: Point,
|
||||
},
|
||||
Led {
|
||||
id: String,
|
||||
value: u32,
|
||||
},
|
||||
Switch {
|
||||
id: String,
|
||||
value: u32,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub enum Message {
|
||||
Shutdown,
|
||||
|
@ -632,6 +697,7 @@ pub enum Message {
|
|||
DeleteScripts(Vec<String>),
|
||||
RequestInput(Vec<InputClass>),
|
||||
UpdateScene(String, Vec<ScriptItem>),
|
||||
InputEvent(InputEvent),
|
||||
}
|
||||
|
||||
impl From<elixir_types::DriverConfig> for Message {
|
||||
|
|
|
@ -8,7 +8,7 @@ use clap::Parser;
|
|||
use ipc_channel::ipc;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
|
||||
use message::{OnClose, Orientation};
|
||||
use message::{InputClass, OnClose, Orientation};
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::dpi::{LogicalPosition, LogicalSize};
|
||||
use winit::event::WindowEvent;
|
||||
|
@ -38,7 +38,7 @@ fn main() -> anyhow::Result<()> {
|
|||
let sender = IpcSender::connect(args.ipc_channel)?;
|
||||
|
||||
let (c2s_send, c2s_recv) = ipc::channel()?;
|
||||
let (_s2c_send, s2c_recv) = ipc::channel()?;
|
||||
let (s2c_send, s2c_recv) = ipc::channel()?;
|
||||
sender.send(IpcExchange {
|
||||
sender: c2s_send,
|
||||
receiver: s2c_recv,
|
||||
|
@ -60,7 +60,7 @@ fn main() -> anyhow::Result<()> {
|
|||
};
|
||||
});
|
||||
|
||||
let mut state = Application::new(msg);
|
||||
let mut state = Application::new(msg, s2c_send);
|
||||
event_loop.run_app(&mut state).map_err(Into::into)
|
||||
} else {
|
||||
panic!("Server: Invalid message received {:?}", msg);
|
||||
|
@ -80,10 +80,12 @@ struct Application {
|
|||
height: u32,
|
||||
on_close: OnClose,
|
||||
window: Option<Window>,
|
||||
input_classes: Vec<InputClass>,
|
||||
sender: IpcSender<Message>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
fn new(event: Message) -> Self {
|
||||
fn new(event: Message, sender: IpcSender<Message>) -> Self {
|
||||
match event {
|
||||
Message::Init {
|
||||
opacity,
|
||||
|
@ -110,6 +112,18 @@ impl Application {
|
|||
height,
|
||||
on_close,
|
||||
window: None,
|
||||
input_classes: vec![
|
||||
InputClass::CursorButton,
|
||||
InputClass::CursorScroll,
|
||||
InputClass::CursorPos,
|
||||
InputClass::Codepoint,
|
||||
InputClass::Key,
|
||||
InputClass::Viewport,
|
||||
InputClass::Relative,
|
||||
InputClass::Led,
|
||||
InputClass::Switch,
|
||||
],
|
||||
sender,
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -127,7 +141,47 @@ impl ApplicationHandler<Message> for Application {
|
|||
_window_id: WindowId,
|
||||
event: WindowEvent,
|
||||
) {
|
||||
println!("window event {:?}", event)
|
||||
match event {
|
||||
WindowEvent::KeyboardInput { event, .. } => {
|
||||
// From cairo driver:
|
||||
//
|
||||
// int action = (event->type == GDK_KEY_PRESS) ? 1 : 0;
|
||||
// uint32_t unicode = gdk_keyval_to_unicode(event->keyval);
|
||||
// send_key(KEYMAP_GDK, event->keyval, event->hardware_keycode, action, event->state);
|
||||
// if (!(event->keyval & 0xF000) && event->type == GDK_KEY_PRESS) {
|
||||
// send_codepoint(KEYMAP_GDK, unicode, event->state);
|
||||
// }
|
||||
// return TRUE;
|
||||
//
|
||||
// Basically, always send a Key event and sometimes a Codepoint event.
|
||||
}
|
||||
WindowEvent::CloseRequested => {
|
||||
self.sender.send(Message::Shutdown).unwrap();
|
||||
}
|
||||
WindowEvent::Destroyed => {
|
||||
self.sender.send(Message::Shutdown).unwrap();
|
||||
}
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
// Send an CursorPos event.
|
||||
}
|
||||
WindowEvent::MouseInput { state, button, .. } => {
|
||||
// Send a CursorButton event.
|
||||
}
|
||||
WindowEvent::AxisMotion { axis, value, .. } => {
|
||||
// Send a CursorScroll event.
|
||||
}
|
||||
WindowEvent::CursorEntered { device_id } => {
|
||||
// Send a ViewPort { event: ViewPortEvent::Enter, position: ?? }
|
||||
}
|
||||
WindowEvent::CursorLeft { device_id } => {
|
||||
// Send a ViewPort { event: ViewPortEvent::Exit, position: ?? }
|
||||
}
|
||||
WindowEvent::Resized(size) => {
|
||||
// Send a ViewPort { event: ViewPortEvent::Reshape, position: Point(size.x, size.y) }
|
||||
}
|
||||
|
||||
_ => println!("unhandled window event {:?}", event),
|
||||
}
|
||||
}
|
||||
|
||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue