neovim-gtk/src/ui.rs

222 lines
5.5 KiB
Rust
Raw Normal View History

2017-03-26 11:34:38 +00:00
use std::cell::{RefCell, Ref, RefMut};
2016-03-31 10:09:34 +00:00
use std::thread;
2016-03-31 16:19:08 +00:00
2016-03-16 15:25:25 +00:00
use gtk;
use gtk_sys;
2016-03-16 15:25:25 +00:00
use gtk::prelude::*;
2017-03-31 20:19:50 +00:00
use gtk::{ApplicationWindow, HeaderBar, ToolButton, Image, AboutDialog};
2017-03-16 10:18:13 +00:00
use gdk::Event;
2017-03-31 20:19:50 +00:00
use gio::{Menu, MenuItem, SimpleAction};
use glib::variant::Variant;
2017-03-16 10:18:13 +00:00
use neovim_lib::NeovimApi;
2016-03-16 15:25:25 +00:00
2017-03-13 15:03:32 +00:00
use settings;
use shell::{Shell, NvimMode};
2017-03-16 10:18:13 +00:00
use nvim::ErrorReport;
2016-03-19 08:47:23 +00:00
2017-03-13 15:03:32 +00:00
macro_rules! ui_thread_var {
($id:ident, $ty:ty, $expr:expr) => (thread_local!(pub static $id: RefCell<$ty> = {
2017-03-26 11:34:38 +00:00
assert_ui_thread();
2017-03-13 15:03:32 +00:00
RefCell::new($expr)
});)
}
ui_thread_var!(UI, Ui, Ui::new());
ui_thread_var!(SH, Shell, Shell::new());
ui_thread_var!(SET, settings::Settings, settings::Settings::new());
2016-03-31 10:09:34 +00:00
2016-05-04 06:23:39 +00:00
#[macro_export]
macro_rules! SHELL {
(&$id:ident = $expr:expr) => (
SH.with(|shell_cell| {
let $id = &shell_cell.borrow();
$expr
});
);
($id:ident = $expr:expr) => (
SH.with(|shell_cell| {
let mut $id = &mut shell_cell.borrow_mut();
$expr
});
);
}
2016-03-19 10:27:39 +00:00
pub struct Ui {
2017-03-14 20:12:31 +00:00
pub initialized: bool,
pub window: Option<ApplicationWindow>,
2017-03-07 14:12:22 +00:00
header_bar: HeaderBar,
2016-03-19 10:27:39 +00:00
}
2016-03-16 15:25:25 +00:00
impl Ui {
pub fn new() -> Ui {
2016-03-19 10:27:39 +00:00
Ui {
2017-03-06 13:58:10 +00:00
window: None,
2017-03-07 14:12:22 +00:00
header_bar: HeaderBar::new(),
2017-03-14 20:12:31 +00:00
initialized: false,
2016-03-19 10:27:39 +00:00
}
2016-03-16 15:25:25 +00:00
}
2017-03-16 10:18:13 +00:00
pub fn close_window(&self) {
2017-03-06 13:58:10 +00:00
self.window.as_ref().unwrap().destroy();
}
2017-03-16 10:18:13 +00:00
pub fn destroy(&mut self) {
self.close_window();
SHELL!(shell = {
shell.nvim().ui_detach().expect("Error in ui_detach");
});
2017-03-16 10:18:13 +00:00
}
2017-03-06 13:58:10 +00:00
pub fn init(&mut self, app: &gtk::Application) {
if self.initialized {
return;
2017-03-14 20:12:31 +00:00
}
self.initialized = true;
2017-03-31 20:19:50 +00:00
self.create_main_menu(app);
SHELL!(shell = {
SET.with(|settings| {
let mut settings = settings.borrow_mut();
settings.init(&mut shell);
});
self.header_bar.set_show_close_button(true);
2016-03-17 13:58:21 +00:00
let save_image = Image::new_from_icon_name("document-save",
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32);
let save_btn = ToolButton::new(Some(&save_image), None);
save_btn.connect_clicked(|_| edit_save_all());
self.header_bar.pack_start(&save_btn);
2016-03-17 13:58:21 +00:00
let paste_image = Image::new_from_icon_name("edit-paste",
gtk_sys::GTK_ICON_SIZE_SMALL_TOOLBAR as i32);
let paste_btn = ToolButton::new(Some(&paste_image), None);
paste_btn.connect_clicked(|_| edit_paste());
self.header_bar.pack_start(&paste_btn);
2016-03-17 13:58:21 +00:00
shell.init();
2016-03-16 15:25:25 +00:00
self.window = Some(ApplicationWindow::new(app));
let window = self.window.as_ref().unwrap();
2017-03-06 13:58:10 +00:00
window.set_titlebar(Some(&self.header_bar));
window.add(&shell.drawing_area);
window.show_all();
window.connect_delete_event(gtk_delete);
window.set_title("Neovim-gtk");
2017-03-06 21:05:48 +00:00
shell.add_configure_event();
});
2017-03-06 21:05:48 +00:00
}
2017-03-31 20:19:50 +00:00
fn create_main_menu(&self, app: &gtk::Application) {
let menu = Menu::new();
let help = Menu::new();
let about = MenuItem::new("About", None);
about.set_detailed_action("app.HelpAbout");
help.append_item(&about);
menu.append_item(&MenuItem::new_submenu("Help", &help));
app.set_menubar(Some(&menu));
let about_action = SimpleAction::new("HelpAbout", None);
about_action.connect_activate(on_help_about);
about_action.set_enabled(true);
app.add_action(&about_action);
}
}
fn on_help_about(_: &SimpleAction, _: &Option<Variant>) {
UI.with(|ui_cell| {
let ui = ui_cell.borrow();
let about = AboutDialog::new();
about.set_transient_for(ui.window.as_ref());
about.set_program_name("NeovimGtk");
about.set_version(env!("CARGO_PKG_VERSION"));
about.set_logo(None);
about.set_authors(&[env!("CARGO_PKG_AUTHORS")]);
about.connect_response(|about, _| about.destroy());
about.show();
});
}
2017-03-07 14:12:22 +00:00
fn edit_paste() {
SHELL!(shell = {
let paste_command = if shell.mode == NvimMode::Normal {
2017-03-08 19:22:58 +00:00
"\"*p"
} else {
2017-03-14 19:51:26 +00:00
"<Esc>\"*pa"
2017-03-08 19:22:58 +00:00
};
let mut nvim = shell.nvim();
2017-03-09 13:18:13 +00:00
nvim.input(paste_command).report_err(nvim);
2017-03-07 14:12:22 +00:00
});
}
fn edit_save_all() {
SHELL!(shell = {
let mut nvim = shell.nvim();
2017-03-09 13:18:13 +00:00
nvim.command(":wa").report_err(nvim);
2017-03-07 10:52:01 +00:00
});
}
2016-05-05 13:48:21 +00:00
fn quit() {
2016-05-04 08:52:57 +00:00
UI.with(|ui_cell| {
let mut ui = ui_cell.borrow_mut();
2017-03-06 13:58:10 +00:00
ui.destroy();
2016-05-04 08:52:57 +00:00
});
2016-05-05 13:48:21 +00:00
}
2017-03-06 13:58:10 +00:00
fn gtk_delete(_: &ApplicationWindow, _: &Event) -> Inhibit {
2016-05-05 13:48:21 +00:00
quit();
2016-05-04 08:52:57 +00:00
Inhibit(false)
}
2017-03-26 11:34:38 +00:00
pub struct UiMutex<T: ?Sized> {
data: RefCell<T>,
}
unsafe impl<T: ?Sized + Send> Send for UiMutex<T> {}
unsafe impl<T: ?Sized + Send> Sync for UiMutex<T> {}
impl<T> UiMutex<T> {
pub fn new(t: T) -> UiMutex<T> {
UiMutex { data: RefCell::new(t) }
}
}
impl<T: ?Sized> UiMutex<T> {
pub fn borrow(&self) -> Ref<T> {
assert_ui_thread();
self.data.borrow()
}
pub fn borrow_mut(&self) -> RefMut<T> {
assert_ui_thread();
self.data.borrow_mut()
}
}
#[inline]
fn assert_ui_thread() {
match thread::current().name() {
Some("main") => (),
Some(ref name) => {
panic!("Can create UI only from main thread, {}", name);
}
None => panic!("Can create UI only from main thread, current thiread has no name"),
}
}