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