2016-09-01 13:24:20 -04:00
|
|
|
//! Process window events
|
2016-12-26 18:33:27 -05:00
|
|
|
use std::borrow::Cow;
|
2016-11-19 19:16:20 -05:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::Write;
|
2016-12-29 15:30:30 -05:00
|
|
|
use std::sync::mpsc;
|
2016-09-01 13:24:20 -04:00
|
|
|
|
2016-12-29 15:30:30 -05:00
|
|
|
use serde_json as json;
|
|
|
|
use parking_lot::MutexGuard;
|
2016-12-26 18:33:27 -05:00
|
|
|
use glutin::{self, ElementState};
|
2016-12-11 01:44:13 -05:00
|
|
|
|
2016-12-12 12:31:48 -05:00
|
|
|
use config::Config;
|
|
|
|
use display::OnResize;
|
2016-12-29 15:30:30 -05:00
|
|
|
use index::{Line, Column, Side};
|
2016-12-26 18:33:27 -05:00
|
|
|
use input::{self, ActionContext, MouseBinding, KeyBinding};
|
2016-12-22 13:43:06 -05:00
|
|
|
use selection::Selection;
|
2016-09-23 13:12:11 -04:00
|
|
|
use sync::FairMutex;
|
2016-12-12 12:31:48 -05:00
|
|
|
use term::{Term, SizeInfo};
|
2016-12-29 20:39:30 -05:00
|
|
|
use util::limit;
|
2016-12-12 12:31:48 -05:00
|
|
|
use window::Window;
|
2016-09-01 13:24:20 -04:00
|
|
|
|
2016-12-26 18:33:27 -05:00
|
|
|
/// Byte sequences are sent to a `Notify` in response to some events
|
|
|
|
pub trait Notify {
|
|
|
|
/// Notify that an escape sequence should be written to the pty
|
|
|
|
///
|
|
|
|
/// TODO this needs to be able to error somehow
|
|
|
|
fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, B);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// State of the mouse
|
|
|
|
pub struct Mouse {
|
|
|
|
pub x: u32,
|
|
|
|
pub y: u32,
|
|
|
|
pub left_button_state: ElementState,
|
|
|
|
pub scroll_px: i32,
|
|
|
|
pub line: Line,
|
|
|
|
pub column: Column,
|
|
|
|
pub cell_side: Side
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Mouse {
|
|
|
|
fn default() -> Mouse {
|
|
|
|
Mouse {
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
left_button_state: ElementState::Released,
|
|
|
|
scroll_px: 0,
|
|
|
|
line: Line(0),
|
|
|
|
column: Column(0),
|
|
|
|
cell_side: Side::Left,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-01 13:24:20 -04:00
|
|
|
/// The event processor
|
2016-12-26 18:33:27 -05:00
|
|
|
///
|
|
|
|
/// Stores some state from received events and dispatches actions when they are
|
|
|
|
/// triggered.
|
2016-09-24 19:11:50 -04:00
|
|
|
pub struct Processor<N> {
|
2016-12-26 18:33:27 -05:00
|
|
|
key_bindings: Vec<KeyBinding>,
|
|
|
|
mouse_bindings: Vec<MouseBinding>,
|
2016-09-24 19:11:50 -04:00
|
|
|
notifier: N,
|
2016-12-26 18:33:27 -05:00
|
|
|
mouse: Mouse,
|
2016-09-01 13:24:20 -04:00
|
|
|
resize_tx: mpsc::Sender<(u32, u32)>,
|
2016-11-19 19:16:20 -05:00
|
|
|
ref_test: bool,
|
2016-12-26 18:33:27 -05:00
|
|
|
size_info: SizeInfo,
|
2016-12-22 13:43:06 -05:00
|
|
|
pub selection: Selection,
|
2016-09-01 13:24:20 -04:00
|
|
|
}
|
|
|
|
|
2016-12-12 12:31:48 -05:00
|
|
|
/// Notify that the terminal was resized
|
|
|
|
///
|
|
|
|
/// Currently this just forwards the notice to the input processor.
|
|
|
|
impl<N> OnResize for Processor<N> {
|
|
|
|
fn on_resize(&mut self, size: &SizeInfo) {
|
2016-12-26 18:33:27 -05:00
|
|
|
self.size_info = size.to_owned();
|
2016-12-12 12:31:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 18:33:27 -05:00
|
|
|
impl<N: Notify> Processor<N> {
|
2016-09-01 13:24:20 -04:00
|
|
|
/// Create a new event processor
|
|
|
|
///
|
|
|
|
/// Takes a writer which is expected to be hooked up to the write end of a
|
|
|
|
/// pty.
|
2016-09-24 19:11:50 -04:00
|
|
|
pub fn new(
|
|
|
|
notifier: N,
|
2016-11-15 12:38:50 -05:00
|
|
|
resize_tx: mpsc::Sender<(u32, u32)>,
|
|
|
|
config: &Config,
|
2016-11-19 19:16:20 -05:00
|
|
|
ref_test: bool,
|
2016-12-29 15:30:30 -05:00
|
|
|
size_info: SizeInfo,
|
2016-09-24 19:11:50 -04:00
|
|
|
) -> Processor<N> {
|
2016-09-01 13:24:20 -04:00
|
|
|
Processor {
|
2016-12-26 18:33:27 -05:00
|
|
|
key_bindings: config.key_bindings().to_vec(),
|
|
|
|
mouse_bindings: config.mouse_bindings().to_vec(),
|
2016-09-24 19:11:50 -04:00
|
|
|
notifier: notifier,
|
2016-09-01 13:24:20 -04:00
|
|
|
resize_tx: resize_tx,
|
2016-11-19 19:16:20 -05:00
|
|
|
ref_test: ref_test,
|
2016-12-26 18:33:27 -05:00
|
|
|
mouse: Default::default(),
|
2016-12-22 13:43:06 -05:00
|
|
|
selection: Default::default(),
|
2016-12-26 18:33:27 -05:00
|
|
|
size_info: size_info,
|
2016-09-01 13:24:20 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 18:33:27 -05:00
|
|
|
/// Handle events from glutin
|
|
|
|
///
|
|
|
|
/// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
|
|
|
|
fn handle_event<'a>(
|
|
|
|
processor: &mut input::Processor<'a, N>,
|
|
|
|
event: glutin::Event,
|
|
|
|
ref_test: bool,
|
|
|
|
resize_tx: &mpsc::Sender<(u32, u32)>,
|
|
|
|
) {
|
2016-09-01 13:24:20 -04:00
|
|
|
match event {
|
2016-11-19 19:16:20 -05:00
|
|
|
glutin::Event::Closed => {
|
2016-12-26 18:33:27 -05:00
|
|
|
if ref_test {
|
2016-11-19 19:16:20 -05:00
|
|
|
// dump grid state
|
2016-12-26 18:33:27 -05:00
|
|
|
let grid = processor.ctx.terminal.grid();
|
2016-11-19 19:16:20 -05:00
|
|
|
|
|
|
|
let serialized_grid = json::to_string(&grid)
|
|
|
|
.expect("serialize grid");
|
|
|
|
|
2016-12-26 18:33:27 -05:00
|
|
|
let serialized_size = json::to_string(processor.ctx.terminal.size_info())
|
2016-11-19 19:16:20 -05:00
|
|
|
.expect("serialize size");
|
|
|
|
|
|
|
|
File::create("./grid.json")
|
|
|
|
.and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
|
|
|
|
.expect("write grid.json");
|
|
|
|
|
|
|
|
File::create("./size.json")
|
|
|
|
.and_then(|mut f| f.write_all(serialized_size.as_bytes()))
|
|
|
|
.expect("write size.json");
|
|
|
|
}
|
|
|
|
|
2017-01-06 14:22:47 -05:00
|
|
|
// FIXME should do a more graceful shutdown
|
|
|
|
::std::process::exit(0);
|
2016-11-19 19:16:20 -05:00
|
|
|
},
|
2016-09-01 13:24:20 -04:00
|
|
|
glutin::Event::Resized(w, h) => {
|
2016-12-26 18:33:27 -05:00
|
|
|
resize_tx.send((w, h)).expect("send new size");
|
2016-12-29 21:38:22 -05:00
|
|
|
processor.ctx.terminal.dirty = true;
|
2016-09-01 13:24:20 -04:00
|
|
|
},
|
2016-11-11 22:59:18 -05:00
|
|
|
glutin::Event::KeyboardInput(state, _code, key, mods, string) => {
|
2016-12-26 18:33:27 -05:00
|
|
|
processor.process_key(state, key, mods, string);
|
2016-09-27 01:22:28 -04:00
|
|
|
},
|
|
|
|
glutin::Event::MouseInput(state, button) => {
|
2016-12-26 18:33:27 -05:00
|
|
|
processor.mouse_input(state, button);
|
2016-12-29 21:38:22 -05:00
|
|
|
processor.ctx.terminal.dirty = true;
|
2016-11-23 23:25:37 -05:00
|
|
|
},
|
|
|
|
glutin::Event::MouseMoved(x, y) => {
|
2016-12-29 20:39:30 -05:00
|
|
|
let x = limit(x, 0, processor.ctx.size_info.width as i32);
|
|
|
|
let y = limit(y, 0, processor.ctx.size_info.height as i32);
|
2016-12-26 18:33:27 -05:00
|
|
|
|
2016-12-29 20:39:30 -05:00
|
|
|
processor.mouse_moved(x as u32, y as u32);
|
|
|
|
|
|
|
|
if !processor.ctx.selection.is_empty() {
|
2016-12-29 21:38:22 -05:00
|
|
|
processor.ctx.terminal.dirty = true;
|
2016-11-23 23:25:37 -05:00
|
|
|
}
|
2016-09-01 13:24:20 -04:00
|
|
|
},
|
2016-11-24 22:50:34 -05:00
|
|
|
glutin::Event::MouseWheel(scroll_delta, touch_phase) => {
|
2016-12-26 18:33:27 -05:00
|
|
|
processor.on_mouse_wheel(scroll_delta, touch_phase);
|
2016-11-24 22:50:34 -05:00
|
|
|
},
|
2017-01-06 23:44:51 -05:00
|
|
|
glutin::Event::Focused(true) |
|
2017-01-04 22:53:24 -05:00
|
|
|
glutin::Event::Refresh |
|
2016-12-11 02:32:12 -05:00
|
|
|
glutin::Event::Awakened => {
|
2016-12-29 21:38:22 -05:00
|
|
|
processor.ctx.terminal.dirty = true;
|
2016-12-11 02:32:12 -05:00
|
|
|
},
|
2016-09-01 13:24:20 -04:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Process at least one event and handle any additional queued events.
|
2016-12-29 15:30:30 -05:00
|
|
|
pub fn process_events<'a>(
|
|
|
|
&mut self,
|
|
|
|
term: &'a FairMutex<Term>,
|
|
|
|
window: &Window
|
2016-12-29 21:38:22 -05:00
|
|
|
) -> MutexGuard<'a, Term> {
|
2016-12-29 15:30:30 -05:00
|
|
|
// Terminal is lazily initialized the first time an event is returned
|
|
|
|
// from the blocking WaitEventsIterator. Otherwise, the pty reader would
|
|
|
|
// be blocked the entire time we wait for input!
|
2016-12-29 21:38:22 -05:00
|
|
|
let mut terminal;
|
2016-12-29 15:30:30 -05:00
|
|
|
|
|
|
|
{
|
|
|
|
// Ditto on lazy initialization for context and processor.
|
|
|
|
let context;
|
|
|
|
let mut processor: input::Processor<N>;
|
|
|
|
|
|
|
|
// Convenience macro which curries most arguments to handle_event.
|
|
|
|
macro_rules! process {
|
|
|
|
($event:expr) => {
|
|
|
|
Processor::handle_event(
|
|
|
|
&mut processor,
|
|
|
|
$event,
|
|
|
|
self.ref_test,
|
|
|
|
&self.resize_tx,
|
|
|
|
)
|
|
|
|
}
|
2016-12-26 18:33:27 -05:00
|
|
|
}
|
|
|
|
|
2016-12-29 15:30:30 -05:00
|
|
|
match window.wait_events().next() {
|
|
|
|
Some(event) => {
|
|
|
|
terminal = term.lock();
|
|
|
|
context = ActionContext {
|
2016-12-29 21:38:22 -05:00
|
|
|
terminal: &mut terminal,
|
2016-12-29 15:30:30 -05:00
|
|
|
notifier: &mut self.notifier,
|
|
|
|
selection: &mut self.selection,
|
|
|
|
mouse: &mut self.mouse,
|
|
|
|
size_info: &self.size_info,
|
|
|
|
};
|
|
|
|
|
|
|
|
processor = input::Processor {
|
|
|
|
ctx: context,
|
|
|
|
key_bindings: &self.key_bindings[..],
|
|
|
|
mouse_bindings: &self.mouse_bindings[..]
|
|
|
|
};
|
|
|
|
|
|
|
|
process!(event);
|
|
|
|
},
|
|
|
|
// Glutin guarantees the WaitEventsIterator never returns None.
|
|
|
|
None => unreachable!(),
|
|
|
|
}
|
2016-12-26 18:33:27 -05:00
|
|
|
|
2016-12-29 15:30:30 -05:00
|
|
|
for event in window.poll_events() {
|
2016-12-26 18:33:27 -05:00
|
|
|
process!(event);
|
2016-12-29 15:30:30 -05:00
|
|
|
}
|
2016-09-01 13:24:20 -04:00
|
|
|
}
|
2016-12-11 02:32:12 -05:00
|
|
|
|
2016-12-29 21:38:22 -05:00
|
|
|
terminal
|
2016-09-01 13:24:20 -04:00
|
|
|
}
|
2016-11-15 12:38:50 -05:00
|
|
|
|
|
|
|
pub fn update_config(&mut self, config: &Config) {
|
2016-12-26 18:33:27 -05:00
|
|
|
self.key_bindings = config.key_bindings().to_vec();
|
|
|
|
self.mouse_bindings = config.mouse_bindings().to_vec();
|
2016-11-15 12:38:50 -05:00
|
|
|
}
|
2016-09-01 13:24:20 -04:00
|
|
|
}
|