Move out resize/init code from draw handler

This commit is contained in:
daa84 2017-09-13 17:40:43 +03:00
parent dc8d6d5a70
commit 94747615af
8 changed files with 330 additions and 272 deletions

View File

@ -47,26 +47,29 @@ pub trait RedrawEvents {
fn on_busy(&mut self, busy: bool) -> RepaintMode; fn on_busy(&mut self, busy: bool) -> RepaintMode;
fn popupmenu_show(&mut self, fn popupmenu_show(
menu: &[Vec<&str>], &mut self,
selected: i64, menu: &[Vec<&str>],
row: u64, selected: i64,
col: u64) row: u64,
-> RepaintMode; col: u64,
) -> RepaintMode;
fn popupmenu_hide(&mut self) -> RepaintMode; fn popupmenu_hide(&mut self) -> RepaintMode;
fn popupmenu_select(&mut self, selected: i64) -> RepaintMode; fn popupmenu_select(&mut self, selected: i64) -> RepaintMode;
fn tabline_update(&mut self, fn tabline_update(
selected: Tabpage, &mut self,
tabs: Vec<(Tabpage, Option<String>)>) selected: Tabpage,
-> RepaintMode; tabs: Vec<(Tabpage, Option<String>)>,
) -> RepaintMode;
fn mode_info_set(&mut self, fn mode_info_set(
cursor_style_enabled: bool, &mut self,
mode_info: Vec<ModeInfo>) cursor_style_enabled: bool,
-> RepaintMode; mode_info: Vec<ModeInfo>,
) -> RepaintMode;
} }
pub trait GuiApi { pub trait GuiApi {
@ -116,19 +119,19 @@ pub enum CursorShape {
impl CursorShape { impl CursorShape {
fn new(shape_code: &Value) -> Result<CursorShape, String> { fn new(shape_code: &Value) -> Result<CursorShape, String> {
let str_code = shape_code let str_code = shape_code.as_str().ok_or_else(|| {
.as_str() "Can't convert cursor shape to string".to_owned()
.ok_or_else(|| "Can't convert cursor shape to string".to_owned())?; })?;
Ok(match str_code { Ok(match str_code {
"block" => CursorShape::Block, "block" => CursorShape::Block,
"horizontal" => CursorShape::Horizontal, "horizontal" => CursorShape::Horizontal,
"vertical" => CursorShape::Vertical, "vertical" => CursorShape::Vertical,
_ => { _ => {
error!("Unknown cursor_shape {}", str_code); error!("Unknown cursor_shape {}", str_code);
CursorShape::Unknown CursorShape::Unknown
} }
}) })
} }
} }
@ -155,9 +158,9 @@ impl ModeInfo {
}; };
Ok(ModeInfo { Ok(ModeInfo {
cursor_shape, cursor_shape,
cell_percentage, cell_percentage,
}) })
} }
pub fn cursor_shape(&self) -> Option<&CursorShape> { pub fn cursor_shape(&self) -> Option<&CursorShape> {
@ -177,7 +180,8 @@ pub struct NvimInitError {
impl NvimInitError { impl NvimInitError {
pub fn new_post_init<E>(error: E) -> NvimInitError pub fn new_post_init<E>(error: E) -> NvimInitError
where E: Into<Box<error::Error>> where
E: Into<Box<error::Error>>,
{ {
NvimInitError { NvimInitError {
cmd: None, cmd: None,
@ -186,7 +190,8 @@ impl NvimInitError {
} }
pub fn new<E>(cmd: &Command, error: E) -> NvimInitError pub fn new<E>(cmd: &Command, error: E) -> NvimInitError
where E: Into<Box<error::Error>> where
E: Into<Box<error::Error>>,
{ {
NvimInitError { NvimInitError {
cmd: Some(format!("{:?}", cmd)), cmd: Some(format!("{:?}", cmd)),
@ -219,9 +224,10 @@ impl error::Error for NvimInitError {
} }
} }
pub fn start(shell: Arc<UiMutex<shell::State>>, pub fn start(
nvim_bin_path: Option<&String>) shell: Arc<UiMutex<shell::State>>,
-> result::Result<Neovim, NvimInitError> { nvim_bin_path: Option<&String>,
) -> result::Result<Neovim, NvimInitError> {
let mut cmd = if let Some(path) = nvim_bin_path { let mut cmd = if let Some(path) = nvim_bin_path {
Command::new(path) Command::new(path)
} else { } else {
@ -237,11 +243,14 @@ pub fn start(shell: Arc<UiMutex<shell::State>>,
.stderr(Stdio::inherit()); .stderr(Stdio::inherit());
if let Ok(runtime_path) = env::var("NVIM_GTK_RUNTIME_PATH") { if let Ok(runtime_path) = env::var("NVIM_GTK_RUNTIME_PATH") {
cmd.arg("--cmd") cmd.arg("--cmd").arg(
.arg(format!("let &rtp.=',{}'", runtime_path)); format!("let &rtp.=',{}'", runtime_path),
);
} else if let Some(prefix) = option_env!("PREFIX") { } else if let Some(prefix) = option_env!("PREFIX") {
cmd.arg("--cmd") cmd.arg("--cmd").arg(format!(
.arg(format!("let &rtp.=',{}/share/nvim-gtk/runtime'", prefix)); "let &rtp.=',{}/share/nvim-gtk/runtime'",
prefix
));
} else { } else {
cmd.arg("--cmd").arg("let &rtp.=',runtime'"); cmd.arg("--cmd").arg("let &rtp.=',runtime'");
} }
@ -255,28 +264,33 @@ pub fn start(shell: Arc<UiMutex<shell::State>>,
let mut nvim = Neovim::new(session); let mut nvim = Neovim::new(session);
nvim.session nvim.session.start_event_loop_handler(
.start_event_loop_handler(NvimHandler::new(shell)); NvimHandler::new(shell),
);
Ok(nvim) Ok(nvim)
} }
pub fn post_start_init(nvim: &mut Neovim, pub fn post_start_init(
open_path: Option<&String>, nvim: &mut Neovim,
cols: u64, open_path: Option<&String>,
rows: u64) cols: u64,
-> result::Result<(), NvimInitError> { rows: u64,
) -> result::Result<(), NvimInitError> {
let mut opts = UiAttachOptions::new(); let mut opts = UiAttachOptions::new();
opts.set_popupmenu_external(false); opts.set_popupmenu_external(false);
opts.set_tabline_external(true); opts.set_tabline_external(true);
nvim.ui_attach(cols, rows, opts) nvim.ui_attach(cols, rows, opts).map_err(
.map_err(NvimInitError::new_post_init)?; NvimInitError::new_post_init,
nvim.command("runtime! ginit.vim") )?;
.map_err(NvimInitError::new_post_init)?; nvim.command("runtime! ginit.vim").map_err(
NvimInitError::new_post_init,
)?;
if let Some(path) = open_path { if let Some(path) = open_path {
nvim.command(&format!("e {}", path)) nvim.command(&format!("e {}", path)).map_err(
.map_err(NvimInitError::new_post_init)?; NvimInitError::new_post_init,
)?;
} }
Ok(()) Ok(())
@ -325,10 +339,10 @@ impl NvimHandler {
if let Some(ev_name) = params[0].as_str().map(String::from) { if let Some(ev_name) = params[0].as_str().map(String::from) {
let args = params.iter().skip(1).cloned().collect(); let args = params.iter().skip(1).cloned().collect();
self.safe_call(move |ui| { self.safe_call(move |ui| {
call_gui_event(ui, &ev_name, &args)?; call_gui_event(ui, &ev_name, &args)?;
ui.on_redraw(&RepaintMode::All); ui.on_redraw(&RepaintMode::All);
Ok(()) Ok(())
}); });
} else { } else {
println!("Unsupported event {:?}", params); println!("Unsupported event {:?}", params);
} }
@ -343,15 +357,16 @@ impl NvimHandler {
} }
fn safe_call<F>(&self, cb: F) fn safe_call<F>(&self, cb: F)
where F: Fn(&mut shell::State) -> result::Result<(), String> + 'static + Send where
F: Fn(&mut shell::State) -> result::Result<(), String> + 'static + Send,
{ {
let shell = self.shell.clone(); let shell = self.shell.clone();
glib::idle_add(move || { glib::idle_add(move || {
if let Err(msg) = cb(&mut shell.borrow_mut()) { if let Err(msg) = cb(&mut shell.borrow_mut()) {
println!("Error call function: {}", msg); println!("Error call function: {}", msg);
} }
glib::Continue(false) glib::Continue(false)
}); });
} }
} }
@ -362,21 +377,24 @@ impl Handler for NvimHandler {
} }
fn call_gui_event(ui: &mut shell::State, fn call_gui_event(
method: &str, ui: &mut shell::State,
args: &Vec<Value>) method: &str,
-> result::Result<(), String> { args: &Vec<Value>,
) -> result::Result<(), String> {
match method { match method {
"Font" => ui.set_font(try_str!(args[0])), "Font" => ui.set_font(try_str!(args[0])),
"Option" => { "Option" => {
match try_str!(args[0]) { match try_str!(args[0]) {
"Popupmenu" => { "Popupmenu" => {
ui.nvim() ui.nvim()
.unwrap()
.set_option(UiOption::ExtPopupmenu(try_uint!(args[1]) == 1)) .set_option(UiOption::ExtPopupmenu(try_uint!(args[1]) == 1))
.map_err(|e| e.to_string())? .map_err(|e| e.to_string())?
} }
"Tabline" => { "Tabline" => {
ui.nvim() ui.nvim()
.unwrap()
.set_option(UiOption::ExtTabline(try_uint!(args[1]) == 1)) .set_option(UiOption::ExtTabline(try_uint!(args[1]) == 1))
.map_err(|e| e.to_string())? .map_err(|e| e.to_string())?
} }
@ -388,10 +406,11 @@ fn call_gui_event(ui: &mut shell::State,
Ok(()) Ok(())
} }
fn call(ui: &mut shell::State, fn call(
method: &str, ui: &mut shell::State,
args: &[Value]) method: &str,
-> result::Result<RepaintMode, String> { args: &[Value],
) -> result::Result<RepaintMode, String> {
let repaint_mode = match method { let repaint_mode = match method {
"cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])), "cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])),
"put" => ui.on_put(try_str!(args[0])), "put" => ui.on_put(try_str!(args[0])),
@ -407,10 +426,12 @@ fn call(ui: &mut shell::State,
} }
"eol_clear" => ui.on_eol_clear(), "eol_clear" => ui.on_eol_clear(),
"set_scroll_region" => { "set_scroll_region" => {
ui.on_set_scroll_region(try_uint!(args[0]), ui.on_set_scroll_region(
try_uint!(args[1]), try_uint!(args[0]),
try_uint!(args[2]), try_uint!(args[1]),
try_uint!(args[3])); try_uint!(args[2]),
try_uint!(args[3]),
);
RepaintMode::Nothing RepaintMode::Nothing
} }
"scroll" => ui.on_scroll(try_int!(args[0])), "scroll" => ui.on_scroll(try_int!(args[0])),
@ -424,15 +445,17 @@ fn call(ui: &mut shell::State,
"busy_stop" => ui.on_busy(false), "busy_stop" => ui.on_busy(false),
"popupmenu_show" => { "popupmenu_show" => {
let menu_items = map_array!(args[0], "Error get menu list array", |item| { let menu_items = map_array!(args[0], "Error get menu list array", |item| {
map_array!(item, map_array!(item, "Error get menu item array", |col| {
"Error get menu item array", col.as_str().ok_or("Error get menu column")
|col| col.as_str().ok_or("Error get menu column")) })
})?; })?;
ui.popupmenu_show(&menu_items, ui.popupmenu_show(
try_int!(args[1]), &menu_items,
try_uint!(args[2]), try_int!(args[1]),
try_uint!(args[3])) try_uint!(args[2]),
try_uint!(args[3]),
)
} }
"popupmenu_hide" => ui.popupmenu_hide(), "popupmenu_hide" => ui.popupmenu_hide(),
"popupmenu_select" => ui.popupmenu_select(try_int!(args[0])), "popupmenu_select" => ui.popupmenu_select(try_int!(args[0])),
@ -442,9 +465,9 @@ fn call(ui: &mut shell::State,
.ok_or_else(|| "Error get map for tab".to_owned()) .ok_or_else(|| "Error get map for tab".to_owned())
.and_then(|tab_map| tab_map.to_attrs_map()) .and_then(|tab_map| tab_map.to_attrs_map())
.map(|tab_attrs| { .map(|tab_attrs| {
let name_attr = tab_attrs let name_attr = tab_attrs.get("name").and_then(
.get("name") |n| n.as_str().map(|s| s.to_owned()),
.and_then(|n| n.as_str().map(|s| s.to_owned())); );
let tab_attr = tab_attrs let tab_attr = tab_attrs
.get("tab") .get("tab")
.map(|tab_id| Tabpage::new(tab_id.clone())) .map(|tab_id| Tabpage::new(tab_id.clone()))
@ -456,13 +479,15 @@ fn call(ui: &mut shell::State,
ui.tabline_update(Tabpage::new(args[0].clone()), tabs_out) ui.tabline_update(Tabpage::new(args[0].clone()), tabs_out)
} }
"mode_info_set" => { "mode_info_set" => {
let mode_info = map_array!(args[1], let mode_info = map_array!(
"Error get array key value for mode_info".to_owned(), args[1],
|mi| { "Error get array key value for mode_info".to_owned(),
mi.as_map() |mi| {
.ok_or_else(|| "Erro get map for mode_info".to_owned()) mi.as_map()
.and_then(|mi_map| ModeInfo::new(mi_map)) .ok_or_else(|| "Erro get map for mode_info".to_owned())
})?; .and_then(|mi_map| ModeInfo::new(mi_map))
}
)?;
ui.mode_info_set(try_bool!(args[0]), mode_info) ui.mode_info_set(try_bool!(args[0]), mode_info)
} }
_ => { _ => {

View File

@ -245,15 +245,17 @@ impl Projects {
fn load_oldfiles(&mut self) { fn load_oldfiles(&mut self) {
let shell_borrow = self.shell.borrow(); let shell_borrow = self.shell.borrow();
let shell_state = shell_borrow.state.borrow_mut(); let shell_state = shell_borrow.state.borrow_mut();
let mut nvim = shell_state.nvim();
let store = EntryStore::load(&mut nvim); let nvim = shell_state.nvim();
store.populate(&self.get_list_store(), None); if let Some(mut nvim) = nvim {
self.store = Some(store); let store = EntryStore::load(&mut nvim);
store.populate(&self.get_list_store(), None);
self.store = Some(store);
}
} }
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.store.take().unwrap().save(); self.store.take().map(|s| s.save());
self.get_list_store().clear(); self.get_list_store().clear();
} }

View File

@ -96,6 +96,5 @@ fn monospace_font_changed(mut shell: &mut Shell, state: &mut State) {
// rpc is priority for font // rpc is priority for font
if state.font_source != FontSource::Rpc { if state.font_source != FontSource::Rpc {
state.update_font(&mut shell); state.update_font(&mut shell);
shell.redraw(&RepaintMode::All);
} }
} }

View File

@ -48,6 +48,12 @@ macro_rules! idle_cb_call {
) )
} }
enum ResizeState {
RequestNvimResize(glib::SourceId),
RequestWindowResize,
Wait,
}
pub struct State { pub struct State {
pub model: UiModel, pub model: UiModel,
color_model: ColorModel, color_model: ColorModel,
@ -67,9 +73,7 @@ pub struct State {
im_context: gtk::IMMulticontext, im_context: gtk::IMMulticontext,
error_area: error::ErrorArea, error_area: error::ErrorArea,
request_resize: bool, resize_state: ResizeState,
request_nvim_resize: bool,
resize_timer: Option<glib::SourceId>,
options: ShellOptions, options: ShellOptions,
@ -102,9 +106,7 @@ impl State {
im_context: gtk::IMMulticontext::new(), im_context: gtk::IMMulticontext::new(),
error_area: error::ErrorArea::new(), error_area: error::ErrorArea::new(),
resize_timer: None, resize_state: ResizeState::Wait,
request_resize: false,
request_nvim_resize: false,
options, options,
@ -120,8 +122,12 @@ impl State {
&self.color_model.bg_color &self.color_model.bg_color
} }
pub fn nvim(&self) -> RefMut<Neovim> { pub fn nvim(&self) -> Option<RefMut<Neovim>> {
RefMut::map(self.nvim.borrow_mut(), |n| n.nvim_mut()) if self.nvim.borrow().is_initialized() {
Some(RefMut::map(self.nvim.borrow_mut(), |n| n.nvim_mut()))
} else {
None
}
} }
pub fn nvim_clone(&self) -> Rc<RefCell<NeovimClient>> { pub fn nvim_clone(&self) -> Rc<RefCell<NeovimClient>> {
@ -151,37 +157,36 @@ impl State {
} }
pub fn open_file(&self, path: &str) { pub fn open_file(&self, path: &str) {
let mut nvim = self.nvim(); if let Some(mut nvim) = self.nvim() {
nvim.command(&format!("e {}", path)).report_err(&mut *nvim); nvim.command(&format!("e {}", path)).report_err(&mut *nvim);
}
} }
pub fn cd(&self, path: &str) { pub fn cd(&self, path: &str) {
let mut nvim = self.nvim(); if let Some(mut nvim) = self.nvim() {
nvim.command(&format!("cd {}", path)).report_err(&mut *nvim); nvim.command(&format!("cd {}", path)).report_err(&mut *nvim);
} }
fn request_resize(&mut self) {
self.request_resize = true;
}
fn request_nvim_resize(&mut self) {
self.request_nvim_resize = true;
} }
fn close_popup_menu(&self) { fn close_popup_menu(&self) {
if self.popup_menu.borrow().is_open() { if self.popup_menu.borrow().is_open() {
let mut nvim = self.nvim(); if let Some(mut nvim) = self.nvim() {
nvim.input("<Esc>").report_err(&mut *nvim); nvim.input("<Esc>").report_err(&mut *nvim);
}
} }
} }
fn queue_draw_area<M: AsRef<ModelRect>>(&mut self, rect_list: &[M]) { fn queue_draw_area<M: AsRef<ModelRect>>(&mut self, rect_list: &[M]) {
// extends by items before, then after changes // extends by items before, then after changes
let rects: Vec<_> = rect_list.iter().map(|rect| rect.as_ref().clone()).map(|mut rect| { let rects: Vec<_> = rect_list
rect.extend_by_items(&self.model); .iter()
rect .map(|rect| rect.as_ref().clone())
}).collect(); .map(|mut rect| {
rect.extend_by_items(&self.model);
rect
})
.collect();
self.update_dirty_glyphs(); self.update_dirty_glyphs();
@ -239,6 +244,38 @@ impl State {
self.im_context.reset(); self.im_context.reset();
} }
fn resize_main_window(&mut self) {
match self.resize_state {
ResizeState::RequestNvimResize(_) => return,
_ => (),
}
let &CellMetrics {
line_height,
char_width,
..
} = self.font_ctx.cell_metrics();
let width = self.drawing_area.get_allocated_width();
let height = self.drawing_area.get_allocated_height();
let request_height = (self.model.rows as f64 * line_height) as i32;
let request_width = (self.model.columns as f64 * char_width) as i32;
if width != request_width || height != request_height {
self.resize_state = ResizeState::RequestWindowResize;
let window: gtk::Window = self.drawing_area
.get_toplevel()
.unwrap()
.downcast()
.unwrap();
let (win_width, win_height) = window.get_size();
let h_border = win_width - width;
let v_border = win_height - height;
window.resize(request_width + h_border, request_height + v_border);
}
}
} }
pub struct UiState { pub struct UiState {
@ -419,11 +456,12 @@ impl Shell {
try_nvim_resize(&ref_state); try_nvim_resize(&ref_state);
false false
}); });
}
#[cfg(unix)] let ref_state = self.state.clone();
pub fn redraw(&self, mode: &RepaintMode) { state.drawing_area.connect_size_allocate(
self.state.borrow_mut().on_redraw(mode); move |_, _| init_nvim(&ref_state),
);
} }
#[cfg(unix)] #[cfg(unix)]
@ -445,7 +483,11 @@ impl Shell {
pub fn detach_ui(&mut self) { pub fn detach_ui(&mut self) {
let state = self.state.borrow(); let state = self.state.borrow();
state.nvim().ui_detach().expect("Error in ui_detach");
let nvim = state.nvim();
if let Some(mut nvim) = nvim {
nvim.ui_detach().expect("Error in ui_detach");
}
} }
pub fn edit_paste(&self) { pub fn edit_paste(&self) {
@ -456,14 +498,19 @@ impl Shell {
"<Esc>\"*pa" "<Esc>\"*pa"
}; };
let mut nvim = state.nvim(); let nvim = state.nvim();
nvim.input(paste_command).report_err(&mut *nvim); if let Some(mut nvim) = nvim {
nvim.input(paste_command).report_err(&mut *nvim);
}
} }
pub fn edit_save_all(&self) { pub fn edit_save_all(&self) {
let state = self.state.borrow(); let state = self.state.borrow();
let nvim = &mut *state.nvim();
nvim.command(":wa").report_err(nvim); let nvim = state.nvim();
if let Some(mut nvim) = nvim {
nvim.command(":wa").report_err(&mut *nvim);
}
} }
pub fn set_detach_cb<F>(&self, cb: Option<F>) pub fn set_detach_cb<F>(&self, cb: Option<F>)
@ -544,14 +591,17 @@ fn mouse_input(shell: &mut State, input: &str, state: ModifierType, position: (f
char_width, char_width,
.. ..
} = shell.font_ctx.cell_metrics(); } = shell.font_ctx.cell_metrics();
let mut nvim = shell.nvim();
let (x, y) = position; let (x, y) = position;
let col = (x / char_width).trunc() as u64; let col = (x / char_width).trunc() as u64;
let row = (y / line_height).trunc() as u64; let row = (y / line_height).trunc() as u64;
let input_str = format!("{}<{},{}>", keyval_to_input_string(input, state), col, row); let input_str = format!("{}<{},{}>", keyval_to_input_string(input, state), col, row);
nvim.input(&input_str).expect(
"Can't send mouse input event", let nvim = shell.nvim();
); if let Some(mut nvim) = nvim {
nvim.input(&input_str).expect(
"Can't send mouse input event",
);
}
} }
fn gtk_button_release(ui_state: &mut UiState) -> Inhibit { fn gtk_button_release(ui_state: &mut UiState) -> Inhibit {
@ -567,15 +617,9 @@ fn gtk_motion_notify(shell: &mut State, ui_state: &mut UiState, ev: &EventMotion
} }
fn gtk_draw(state_arc: &Arc<UiMutex<State>>, ctx: &cairo::Context) -> Inhibit { fn gtk_draw(state_arc: &Arc<UiMutex<State>>, ctx: &cairo::Context) -> Inhibit {
if state_arc.borrow_mut().request_nvim_resize {
try_nvim_resize(state_arc);
}
init_nvim(state_arc); let state = state_arc.borrow();
let mut state = state_arc.borrow_mut();
if state.nvim.borrow().is_initialized() { if state.nvim.borrow().is_initialized() {
request_window_resize(&mut *state);
render::render( render::render(
ctx, ctx,
state.cursor.as_ref().unwrap(), state.cursor.as_ref().unwrap(),
@ -664,21 +708,6 @@ fn init_nvim_async(
}); });
} }
fn init_nvim(state_arc: &Arc<UiMutex<State>>) {
let state = state_arc.borrow();
let mut nvim = state.nvim.borrow_mut();
if nvim.is_uninitialized() {
nvim.set_in_progress();
let (cols, rows) = state.calc_nvim_size();
let state_arc = state_arc.clone();
let options = state.options.clone();
thread::spawn(move || init_nvim_async(state_arc, options, cols, rows));
}
}
fn draw_initializing(state: &State, ctx: &cairo::Context) { fn draw_initializing(state: &State, ctx: &cairo::Context) {
let layout = ctx.create_pango_layout(); let layout = ctx.create_pango_layout();
let desc = state.get_font_desc(); let desc = state.get_font_desc();
@ -719,47 +748,32 @@ fn draw_initializing(state: &State, ctx: &cairo::Context) {
); );
} }
fn request_window_resize(state: &mut State) { fn init_nvim(state_ref: &Arc<UiMutex<State>>) {
if !state.request_resize { let state = state_ref.borrow();
return; let mut nvim = state.nvim.borrow_mut();
} if nvim.is_uninitialized() {
if state.resize_timer.is_some() { nvim.set_in_progress();
return;
}
let &CellMetrics { let (cols, rows) = state.calc_nvim_size();
line_height,
char_width,
..
} = state.font_ctx.cell_metrics();
state.request_resize = false;
let width = state.drawing_area.get_allocated_width(); let state_arc = state_ref.clone();
let height = state.drawing_area.get_allocated_height(); let options = state.options.clone();
let request_height = (state.model.rows as f64 * line_height) as i32; thread::spawn(move || init_nvim_async(state_arc, options, cols, rows));
let request_width = (state.model.columns as f64 * char_width) as i32;
if width != request_width || height != request_height {
let window: gtk::Window = state
.drawing_area
.get_toplevel()
.unwrap()
.downcast()
.unwrap();
let (win_width, win_height) = window.get_size();
let h_border = win_width - width;
let v_border = win_height - height;
window.resize(request_width + h_border, request_height + v_border);
} }
} }
fn try_nvim_resize(state: &Arc<UiMutex<State>>) { fn try_nvim_resize(state: &Arc<UiMutex<State>>) {
let mut state_ref = state.borrow_mut(); let mut state_ref = state.borrow_mut();
state_ref.request_nvim_resize = false; match state_ref.resize_state {
ResizeState::RequestWindowResize => {
if let Some(timer) = state_ref.resize_timer { state_ref.resize_state = ResizeState::Wait;
glib::source_remove(timer); return;
}
ResizeState::RequestNvimResize(timer) => {
glib::source_remove(timer);
}
ResizeState::Wait => (),
} }
if !state_ref.nvim.borrow().is_initialized() { if !state_ref.nvim.borrow().is_initialized() {
@ -768,14 +782,17 @@ fn try_nvim_resize(state: &Arc<UiMutex<State>>) {
let (columns, rows) = state_ref.calc_nvim_size(); let (columns, rows) = state_ref.calc_nvim_size();
let state = state.clone(); let state = state.clone();
state_ref.resize_timer = Some(glib::timeout_add(250, move || { state_ref.resize_state = ResizeState::RequestNvimResize(gtk::timeout_add(250, move || {
let mut state_ref = state.borrow_mut(); let mut state_ref = state.borrow_mut();
state_ref.resize_timer = None; state_ref.resize_state = ResizeState::Wait;
if state_ref.model.rows != rows || state_ref.model.columns != columns { if state_ref.model.rows != rows || state_ref.model.columns != columns {
if let Err(err) = state_ref.nvim().ui_try_resize(columns as u64, rows as u64) { let nvim = state_ref.nvim();
error!("Error trying resize nvim {}", err); if let Some(mut nvim) = nvim {
if let Err(err) = nvim.ui_try_resize(columns as u64, rows as u64) {
error!("Error trying resize nvim {}", err);
}
} }
} }
Continue(false) Continue(false)
@ -804,7 +821,8 @@ impl RedrawEvents for State {
fn on_resize(&mut self, columns: u64, rows: u64) -> RepaintMode { fn on_resize(&mut self, columns: u64, rows: u64) -> RepaintMode {
self.model = UiModel::new(rows, columns); self.model = UiModel::new(rows, columns);
self.request_resize(); self.resize_main_window();
RepaintMode::Nothing RepaintMode::Nothing
} }
@ -813,7 +831,7 @@ impl RedrawEvents for State {
RepaintMode::All => { RepaintMode::All => {
self.update_dirty_glyphs(); self.update_dirty_glyphs();
self.drawing_area.queue_draw(); self.drawing_area.queue_draw();
}, }
RepaintMode::Area(ref rect) => self.queue_draw_area(&[rect]), RepaintMode::Area(ref rect) => self.queue_draw_area(&[rect]),
RepaintMode::AreaList(ref list) => self.queue_draw_area(&list.list), RepaintMode::AreaList(ref list) => self.queue_draw_area(&list.list),
RepaintMode::Nothing => (), RepaintMode::Nothing => (),
@ -968,10 +986,12 @@ impl RedrawEvents for State {
impl GuiApi for State { impl GuiApi for State {
fn set_font(&mut self, font_desc: &str) { fn set_font(&mut self, font_desc: &str) {
self.set_font_desc(font_desc); {
self.request_nvim_resize(); let mut settings = self.settings.borrow_mut();
settings.set_font_source(FontSource::Rpc);
}
let mut settings = self.settings.borrow_mut(); self.set_font_desc(font_desc);
settings.set_font_source(FontSource::Rpc); self.resize_main_window();
} }
} }

View File

@ -24,10 +24,7 @@ pub fn can_close_window(comps: &UiMutex<Components>, shell: &RefCell<Shell>) ->
} }
} }
fn show_not_saved_dlg(comps: &UiMutex<Components>, fn show_not_saved_dlg(comps: &UiMutex<Components>, shell: &Shell, changed_bufs: &[String]) -> bool {
shell: &Shell,
changed_bufs: &[String])
-> bool {
let mut changed_files = changed_bufs let mut changed_files = changed_bufs
.iter() .iter()
.map(|n| if n.is_empty() { "<No name>" } else { n }) .map(|n| if n.is_empty() { "<No name>" } else { n })
@ -35,24 +32,30 @@ fn show_not_saved_dlg(comps: &UiMutex<Components>,
changed_files.pop(); changed_files.pop();
let flags = gtk::DIALOG_MODAL | gtk::DIALOG_DESTROY_WITH_PARENT; let flags = gtk::DIALOG_MODAL | gtk::DIALOG_DESTROY_WITH_PARENT;
let dlg = MessageDialog::new(Some(comps.borrow().window()), let dlg = MessageDialog::new(
flags, Some(comps.borrow().window()),
MessageType::Question, flags,
ButtonsType::None, MessageType::Question,
&format!("Save changes to '{}'?", changed_files)); ButtonsType::None,
&format!("Save changes to '{}'?", changed_files),
);
const SAVE_ID: i32 = 0; const SAVE_ID: i32 = 0;
const CLOSE_WITHOUT_SAVE: i32 = 1; const CLOSE_WITHOUT_SAVE: i32 = 1;
const CANCEL_ID: i32 = 2; const CANCEL_ID: i32 = 2;
dlg.add_buttons(&[("_Yes", SAVE_ID), dlg.add_buttons(
("_No", CLOSE_WITHOUT_SAVE), &[
("_Cancel", CANCEL_ID)]); ("_Yes", SAVE_ID),
("_No", CLOSE_WITHOUT_SAVE),
("_Cancel", CANCEL_ID),
],
);
let res = match dlg.run() { let res = match dlg.run() {
SAVE_ID => { SAVE_ID => {
let state = shell.state.borrow(); let state = shell.state.borrow();
let mut nvim = state.nvim(); let mut nvim = state.nvim().unwrap();
match nvim.command("wa") { match nvim.command("wa") {
Err(ref err) => { Err(ref err) => {
println!("Error: {}", err); println!("Error: {}", err);
@ -72,32 +75,46 @@ fn show_not_saved_dlg(comps: &UiMutex<Components>,
fn get_changed_buffers(shell: &Shell) -> Result<Vec<String>, CallError> { fn get_changed_buffers(shell: &Shell) -> Result<Vec<String>, CallError> {
let state = shell.state.borrow(); let state = shell.state.borrow();
let mut nvim = state.nvim(); let nvim = state.nvim();
let buffers = nvim.list_bufs().unwrap(); if let Some(mut nvim) = nvim {
let buffers = nvim.list_bufs().unwrap();
Ok(buffers Ok(
.iter() buffers
.map(|buf| { .iter()
(match buf.get_option(&mut nvim, "modified") { .map(|buf| {
Ok(Value::Boolean(val)) => val, (
Ok(_) => { match buf.get_option(&mut nvim, "modified") {
println!("Value must be boolean"); Ok(Value::Boolean(val)) => val,
false Ok(_) => {
} println!("Value must be boolean");
Err(ref err) => { false
println!("Something going wrong while getting buffer option: {}", err); }
false Err(ref err) => {
} println!(
}, "Something going wrong while getting buffer option: {}",
match buf.get_name(&mut nvim) { err
Ok(name) => name, );
Err(ref err) => { false
println!("Something going wrong while getting buffer name: {}", err); }
"<Error>".to_owned() },
} match buf.get_name(&mut nvim) {
}) Ok(name) => name,
}) Err(ref err) => {
.filter(|e| e.0) println!(
.map(|e| e.1) "Something going wrong while getting buffer name: {}",
.collect()) err
);
"<Error>".to_owned()
}
},
)
})
.filter(|e| e.0)
.map(|e| e.1)
.collect(),
)
} else {
Ok(vec![])
}
} }

View File

@ -27,13 +27,6 @@ impl Item {
} }
} }
#[cfg(test)]
pub fn set_offset(&mut self, offset: i32, length: i32, num_chars: i32) {
self.0.offset = offset;
self.0.length = length;
self.0.num_chars = num_chars;
}
pub fn analysis(&self) -> analysis::Analysis { pub fn analysis(&self) -> analysis::Analysis {
analysis::Analysis::from(&self.0.analysis) analysis::Analysis::from(&self.0.analysis)
} }

View File

@ -231,32 +231,6 @@ mod tests {
assert_eq!(2, list.list.len()); assert_eq!(2, list.list.len());
} }
#[test]
fn test_from_area() {
let rect = ModelRect::from_area(10.0, 5.0, 3.0, 3.0, 9.0, 17.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(10.0, 5.0, 0.0, 0.0, 10.0, 20.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(10.0, 5.0, 0.0, 0.0, 11.0, 21.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(2, rect.bot);
assert_eq!(2, rect.right);
}
#[test] #[test]
fn test_cursor_area() { fn test_cursor_area() {
let mut model = UiModel::new(10, 20); let mut model = UiModel::new(10, 20);

View File

@ -301,4 +301,32 @@ mod tests {
assert_eq!(5, width); assert_eq!(5, width);
assert_eq!(10, height); assert_eq!(10, height);
} }
#[test]
fn test_from_area() {
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 3.0, 3.0, 9.0, 17.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 10.0, 20.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 11.0, 21.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);
assert_eq!(2, rect.bot);
assert_eq!(2, rect.right);
}
} }