1 use crate::platform::{
2     GraphicsContext, InputState, Key, KeyboardInput, LogicalDelta, LogicalPosition, LogicalSize,
3     ModifiersState, MouseButton, WindowEvent, WindowHint,
4 };
5 
6 use glfw;
7 use glfw::Context;
8 
9 use std::{io, sync};
10 
11 ///////////////////////////////////////////////////////////////////////////////
12 
init( title: &str, w: u32, h: u32, hints: &[WindowHint], context: GraphicsContext, ) -> io::Result<(Window, Events)>13 pub fn init(
14     title: &str,
15     w: u32,
16     h: u32,
17     hints: &[WindowHint],
18     context: GraphicsContext,
19 ) -> io::Result<(Window, Events)> {
20     let mut glfw =
21         glfw::init(glfw::FAIL_ON_ERRORS).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
22 
23     glfw.window_hint(glfw::WindowHint::Resizable(true));
24     glfw.window_hint(glfw::WindowHint::Visible(true));
25     glfw.window_hint(glfw::WindowHint::Focused(true));
26     glfw.window_hint(glfw::WindowHint::RefreshRate(None));
27     glfw.window_hint(glfw::WindowHint::ScaleToMonitor(true));
28 
29     match context {
30         GraphicsContext::None => {
31             glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::NoApi));
32         }
33         GraphicsContext::Gl => {
34             glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::OpenGl));
35             glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
36             glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
37             glfw.window_hint(glfw::WindowHint::OpenGlProfile(
38                 glfw::OpenGlProfileHint::Core,
39             ));
40         }
41     }
42 
43     for hint in hints {
44         glfw.window_hint((*hint).into());
45     }
46 
47     let (mut window, events) = glfw
48         .create_window(w, h, title, glfw::WindowMode::Windowed)
49         .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "glfw: error creating window"))?;
50 
51     window.make_current();
52     window.set_all_polling(true);
53 
54     Ok((
55         Window {
56             handle: window,
57             context,
58         },
59         Events {
60             handle: events,
61             glfw,
62         },
63     ))
64 }
65 
66 pub struct Events {
67     handle: sync::mpsc::Receiver<(f64, glfw::WindowEvent)>,
68     glfw: glfw::Glfw,
69 }
70 
71 impl Events {
wait(&mut self)72     pub fn wait(&mut self) {
73         self.glfw.wait_events();
74     }
75 
wait_timeout(&mut self, timeout: std::time::Duration)76     pub fn wait_timeout(&mut self, timeout: std::time::Duration) {
77         self.glfw.wait_events_timeout(timeout.as_secs_f64());
78     }
79 
poll(&mut self)80     pub fn poll(&mut self) {
81         self.glfw.poll_events();
82     }
83 
flush<'a>(&'a self) -> impl Iterator<Item = WindowEvent> + 'a84     pub fn flush<'a>(&'a self) -> impl Iterator<Item = WindowEvent> + 'a {
85         glfw::flush_messages(&self.handle).map(|(_, e)| e.into())
86     }
87 }
88 
89 pub struct Window {
90     pub handle: glfw::Window,
91     context: GraphicsContext,
92 }
93 
94 impl Window {
handle(&self) -> &glfw::Window95     pub fn handle(&self) -> &glfw::Window {
96         &self.handle
97     }
98 
get_proc_address(&mut self, s: &str) -> *const std::ffi::c_void99     pub fn get_proc_address(&mut self, s: &str) -> *const std::ffi::c_void {
100         self.handle.get_proc_address(s)
101     }
102 
set_cursor_visible(&mut self, visible: bool)103     pub fn set_cursor_visible(&mut self, visible: bool) {
104         self.handle.set_cursor_mode(if visible {
105             glfw::CursorMode::Normal
106         } else {
107             glfw::CursorMode::Hidden
108         });
109     }
110 
scale_factor(&self) -> f64111     pub fn scale_factor(&self) -> f64 {
112         let (x, _) = self.handle.get_content_scale();
113         x as f64
114     }
115 
size(&self) -> LogicalSize116     pub fn size(&self) -> LogicalSize {
117         let (w, h) = self.handle.get_size();
118         LogicalSize::new(w as f64, h as f64)
119     }
120 
present(&mut self)121     pub fn present(&mut self) {
122         if self.context == GraphicsContext::Gl {
123             self.handle.swap_buffers();
124         }
125     }
126 
is_closing(&self) -> bool127     pub fn is_closing(&self) -> bool {
128         self.handle.should_close()
129     }
130 
is_focused(&self) -> bool131     pub fn is_focused(&self) -> bool {
132         self.handle.is_focused()
133     }
134 }
135 
136 impl Into<glfw::WindowHint> for WindowHint {
into(self) -> glfw::WindowHint137     fn into(self) -> glfw::WindowHint {
138         match self {
139             Self::Resizable(b) => glfw::WindowHint::Resizable(b),
140             Self::Visible(b) => glfw::WindowHint::Visible(b),
141         }
142     }
143 }
144 
145 impl From<glfw::MouseButton> for MouseButton {
from(button: glfw::MouseButton) -> Self146     fn from(button: glfw::MouseButton) -> Self {
147         match button {
148             glfw::MouseButton::Button1 => MouseButton::Left,
149             glfw::MouseButton::Button2 => MouseButton::Right,
150             glfw::MouseButton::Button3 => MouseButton::Middle,
151             glfw::MouseButton::Button4 => MouseButton::Other(4),
152             glfw::MouseButton::Button5 => MouseButton::Other(5),
153             glfw::MouseButton::Button6 => MouseButton::Other(6),
154             glfw::MouseButton::Button7 => MouseButton::Other(7),
155             glfw::MouseButton::Button8 => MouseButton::Other(8),
156         }
157     }
158 }
159 
160 impl From<glfw::Action> for InputState {
from(state: glfw::Action) -> Self161     fn from(state: glfw::Action) -> Self {
162         match state {
163             glfw::Action::Press => InputState::Pressed,
164             glfw::Action::Release => InputState::Released,
165             glfw::Action::Repeat => InputState::Repeated,
166         }
167     }
168 }
169 
170 impl From<glfw::WindowEvent> for WindowEvent {
from(event: glfw::WindowEvent) -> Self171     fn from(event: glfw::WindowEvent) -> Self {
172         use glfw::WindowEvent as Glfw;
173 
174         match event {
175             // We care about logical ("screen") coordinates, so we
176             // use this event instead of the framebuffer size event.
177             Glfw::Size(w, h) => WindowEvent::Resized(LogicalSize::new(w as f64, h as f64)),
178             Glfw::FramebufferSize(_, _) => WindowEvent::Noop,
179             Glfw::Iconify(true) => WindowEvent::Minimized,
180             Glfw::Iconify(false) => WindowEvent::Restored,
181             Glfw::Close => WindowEvent::CloseRequested,
182             Glfw::Refresh => WindowEvent::RedrawRequested,
183             Glfw::Pos(x, y) => WindowEvent::Moved(LogicalPosition::new(x as f64, y as f64)),
184             Glfw::MouseButton(button, action, modifiers) => WindowEvent::MouseInput {
185                 state: action.into(),
186                 button: button.into(),
187                 modifiers: modifiers.into(),
188             },
189             Glfw::Scroll(x, y) => WindowEvent::MouseWheel {
190                 delta: LogicalDelta { x, y },
191             },
192             Glfw::CursorEnter(true) => WindowEvent::CursorEntered,
193             Glfw::CursorEnter(false) => WindowEvent::CursorLeft,
194             Glfw::CursorPos(x, y) => WindowEvent::CursorMoved {
195                 position: LogicalPosition::new(x, y),
196             },
197             Glfw::Char(c) => WindowEvent::ReceivedCharacter(c),
198             Glfw::Key(key, _, action, modifiers) => WindowEvent::KeyboardInput(KeyboardInput {
199                 key: Some(key.into()),
200                 state: action.into(),
201                 modifiers: modifiers.into(),
202             }),
203             Glfw::Focus(b) => WindowEvent::Focused(b),
204             Glfw::ContentScale(x, y) => {
205                 if (x - y).abs() > 0.1 {
206                     warn!("glfw: content scale isn't uniform: {} x {}", x, y);
207                 }
208                 WindowEvent::ScaleFactorChanged(x as f64)
209             }
210             _ => WindowEvent::Noop,
211         }
212     }
213 }
214 
215 impl From<glfw::Key> for Key {
from(k: glfw::Key) -> Self216     fn from(k: glfw::Key) -> Self {
217         use glfw::Key as Glfw;
218 
219         match k {
220             Glfw::Escape => Key::Escape,
221             Glfw::Insert => Key::Insert,
222             Glfw::Home => Key::Home,
223             Glfw::Delete => Key::Delete,
224             Glfw::End => Key::End,
225             Glfw::PageDown => Key::PageDown,
226             Glfw::PageUp => Key::PageUp,
227             Glfw::Left => Key::Left,
228             Glfw::Up => Key::Up,
229             Glfw::Right => Key::Right,
230             Glfw::Down => Key::Down,
231             Glfw::Backspace => Key::Backspace,
232             Glfw::Enter => Key::Return,
233             Glfw::Space => Key::Space,
234             Glfw::LeftAlt => Key::Alt,
235             Glfw::LeftBracket => Key::LBracket,
236             Glfw::LeftControl => Key::Control,
237             Glfw::LeftShift => Key::Shift,
238             Glfw::RightAlt => Key::Alt,
239             Glfw::RightBracket => Key::RBracket,
240             Glfw::RightControl => Key::Control,
241             Glfw::RightShift => Key::Shift,
242             Glfw::Tab => Key::Tab,
243 
244             _ => {
245                 if let Some(sym) = k.get_name() {
246                     if let Some(c) = sym.chars().next() {
247                         return Key::from(c);
248                     }
249                 }
250                 Key::Unknown
251             }
252         }
253     }
254 }
255 
256 impl From<glfw::Modifiers> for ModifiersState {
from(mods: glfw::Modifiers) -> Self257     fn from(mods: glfw::Modifiers) -> Self {
258         Self {
259             shift: mods.contains(glfw::Modifiers::Shift),
260             ctrl: mods.contains(glfw::Modifiers::Control),
261             alt: mods.contains(glfw::Modifiers::Alt),
262             meta: mods.contains(glfw::Modifiers::Super),
263         }
264     }
265 }
266