glfw/
lib.rs

1// Copyright 2013-2016 The GLFW-RS Developers. For a full listing of the authors,
2// refer to the AUTHORS file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#![crate_type = "lib"]
17#![crate_type = "rlib"]
18#![crate_type = "dylib"]
19#![crate_name = "glfw"]
20#![deny(
21    rust_2018_compatibility,
22    rust_2018_idioms,
23    nonstandard_style,
24    unused,
25    future_incompatible,
26    missing_copy_implementations,
27    missing_debug_implementations,
28    missing_abi,
29    clippy::doc_markdown
30)]
31#![allow(non_upper_case_globals)]
32
33//! An idiomatic wrapper for the GLFW library.
34//!
35//! # Example
36//!
37//! ~~~no_run
38//! extern crate glfw;
39//!
40//! use glfw::{Action, Context, Key};
41//!
42//! fn main() {
43//!    use glfw::fail_on_errors;
44//! let mut glfw = glfw::init(fail_on_errors!()).unwrap();
45//!
46//!     // Create a windowed mode window and its OpenGL context
47//!     let (mut window, events) = glfw.create_window(300, 300, "Hello this is window",
48//! glfw::WindowMode::Windowed)         .expect("Failed to create GLFW window.");
49//!
50//!     // Make the window's context current
51//!     window.make_current();
52//!     window.set_key_polling(true);
53//!
54//!     // Loop until the user closes the window
55//!     while !window.should_close() {
56//!         // Swap front and back buffers
57//!         window.swap_buffers();
58//!
59//!         // Poll for and process events
60//!         glfw.poll_events();
61//!         for (_, event) in glfw::flush_messages(&events) {
62//!             println!("{:?}", event);
63//!             match event {
64//!                 glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
65//!                     window.set_should_close(true)
66//!                 },
67//!                 _ => {},
68//!             }
69//!         }
70//!     }
71//! }
72//! ~~~
73//!
74//! # Cargo Features
75//!
76//! Use the `vulkan` feature flag to enable all Vulkan functions and types.
77//!
78//! Use the `image` feature flag to enable use of the [`image`](https://github.com/PistonDevelopers/image) library for cursors and icons.
79//!
80//! Use the `all` feature flag to enable both at the same time.
81
82// TODO: Document differences between GLFW and glfw-rs
83pub mod ffi {
84    pub use glfw_sys::*;
85}
86macro_rules! make_user_callback_functions {
87    (
88        doc -> $doc:literal,
89        set -> $set:ident,
90        unset -> $unset:ident,
91        poll -> $poll:ident,
92        callback_field -> $callback_field:ident,
93        poll_field -> $poll_field:ident,
94        glfw -> $glfw:ident,
95        args -> ($($args:ty),*),
96        secret -> $secret:ident
97    ) => {
98
99        #[doc = $doc]
100        pub fn $set<T>(&mut self, callback: T)
101        where T: FnMut(&mut Window, $($args),*) + 'static {
102            unsafe {
103                let callbacks = WindowCallbacks::get_callbacks(self.ptr);
104                callbacks.$callback_field = Some(Box::new(callback));
105                ffi::$glfw(self.ptr, Some(Self::$secret));
106            }
107        }
108
109        #[doc = $doc]
110        pub fn $unset(&mut self) {
111            unsafe {
112                let callbacks = WindowCallbacks::get_callbacks(self.ptr);
113                callbacks.$callback_field = None;
114
115                // We're removing the callback, if theres no polling either, set to null
116                if !callbacks.$poll_field {
117                    ffi::$glfw(self.ptr, None);
118                }
119            }
120        }
121
122        #[doc = $doc]
123        pub fn $poll(&mut self, should_poll: bool) {
124            unsafe {
125                let callbacks = WindowCallbacks::get_callbacks(self.ptr);
126                callbacks.$poll_field = should_poll;
127
128                // If no polling and not custom callback, set glfw callback to null
129                if should_poll {
130                    ffi::$glfw(self.ptr, Some(Self::$secret));
131                } else if callbacks.$callback_field.is_none() {
132                    ffi::$glfw(self.ptr, None);
133                }
134            }
135        }
136    }
137}
138
139macro_rules! new_callback {
140    (
141        doc -> $doc:literal,
142        set -> $set:ident,
143        unset -> $unset:ident,
144        poll -> $poll:ident,
145        callback_field -> $callback_field:ident,
146        poll_field -> $poll_field:ident,
147        window_event -> $window_event:ident ($($args:ty),+),
148        glfw -> $glfw:ident ($($glfw_arg_names:ident: $glfw_args:ty),*),
149        convert_args -> ($($convert_args:expr),*),
150        secret -> $secret:ident
151    ) => {
152
153        #[allow(unused_unsafe)]
154        extern "C" fn $secret(glfw_window: *mut GLFWwindow, $($glfw_arg_names: $glfw_args),*) {
155            unsafe {
156                let callbacks = WindowCallbacks::get_callbacks(glfw_window);
157                let window = &mut *callbacks.window_ptr;
158                if let Some(func) = &mut callbacks.$callback_field {
159                    func(window, $($convert_args),*);
160                }
161                if callbacks.$poll_field {
162                    let event = (ffi::glfwGetTime() as f64, WindowEvent::$window_event($($convert_args),*));
163                    if let Some(event) = callbacks::unbuffered::handle(glfw_window as WindowId, event) {
164                        callbacks.sender.send(event);
165                    }
166                }
167            }
168        }
169
170        make_user_callback_functions!(
171            doc -> $doc,
172            set -> $set,
173            unset -> $unset,
174            poll -> $poll,
175            callback_field -> $callback_field,
176            poll_field -> $poll_field,
177            glfw -> $glfw,
178            args -> ($($args),*),
179            secret -> $secret
180        );
181    };
182    (
183        doc -> $doc:literal,
184        set -> $set:ident,
185        unset -> $unset:ident,
186        poll -> $poll:ident,
187        callback_field -> $callback_field:ident,
188        poll_field -> $poll_field:ident,
189        window_event -> $window_event:ident,
190        glfw -> $glfw:ident ($($glfw_arg_names:ident: $glfw_args:ty),*),
191        convert_args -> ($($convert_args:expr),*),
192        secret -> $secret:ident
193    ) => {
194
195        #[allow(unused_unsafe)]
196        extern "C" fn $secret(glfw_window: *mut GLFWwindow, $($glfw_arg_names: $glfw_args),*) {
197            unsafe {
198                let callbacks = WindowCallbacks::get_callbacks(glfw_window);
199                let window = &mut *callbacks.window_ptr;
200                if let Some(func) = &mut callbacks.$callback_field {
201                    func(window);
202                }
203                if callbacks.$poll_field {
204                    let event = (ffi::glfwGetTime() as f64, WindowEvent::$window_event);
205                    if let Some(event) = callbacks::unbuffered::handle(glfw_window as WindowId, event) {
206                        callbacks.sender.send(event);
207                    }
208                }
209            }
210        }
211
212        make_user_callback_functions!(
213            doc -> $doc,
214            set -> $set,
215            unset -> $unset,
216            poll -> $poll,
217            callback_field -> $callback_field,
218            poll_field -> $poll_field,
219            glfw -> $glfw,
220            args -> (),
221            secret -> $secret
222        );
223    }
224}
225
226#[cfg(feature = "log")]
227#[macro_use]
228extern crate log;
229#[macro_use]
230extern crate bitflags;
231#[cfg(feature = "image")]
232#[allow(unused)]
233extern crate image;
234
235#[cfg(feature = "raw-window-handle-v0-6")]
236extern crate raw_window_handle_0_6 as raw_window_handle;
237
238#[cfg(feature = "raw-window-handle-v0-5")]
239extern crate raw_window_handle_0_5 as raw_window_handle;
240
241use std::collections::VecDeque;
242#[allow(unused)]
243use std::ffi::*;
244use std::ffi::{CStr, CString};
245use std::marker::Send;
246use std::ops::{Deref, DerefMut};
247#[cfg(not(target_os = "emscripten"))]
248use std::os::raw::c_void;
249use std::os::raw::{c_char, c_double, c_float, c_int, c_ushort};
250use std::path::PathBuf;
251use std::ptr::{null, null_mut};
252use std::sync::atomic::{AtomicUsize, Ordering};
253use std::sync::mpsc::{channel, Receiver, Sender};
254use std::sync::{Arc, Mutex};
255use std::{error, fmt, mem, ptr, slice};
256
257#[cfg(feature = "raw-window-handle-v0-6")]
258use raw_window_handle::{
259    DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
260};
261#[cfg(feature = "raw-window-handle-v0-5")]
262use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
263use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
264#[cfg(feature = "serde")]
265use serde::{Deserialize, Serialize};
266
267/// Alias to `MouseButton1`, supplied for improved clarity.
268pub use self::MouseButton::Button1 as MouseButtonLeft;
269/// Alias to `MouseButton2`, supplied for improved clarity.
270pub use self::MouseButton::Button2 as MouseButtonRight;
271/// Alias to `MouseButton3`, supplied for improved clarity.
272pub use self::MouseButton::Button3 as MouseButtonMiddle;
273use crate::ffi::GLFWwindow;
274
275mod callbacks;
276
277#[derive(Debug)]
278#[repr(transparent)]
279pub struct PWindow(Box<Window>);
280
281impl PWindow {
282    fn raw_ptr(&mut self) -> *mut Window {
283        self.0.deref_mut()
284    }
285}
286
287impl Deref for PWindow {
288    type Target = Window;
289    fn deref(&self) -> &Self::Target {
290        self.0.deref()
291    }
292}
293
294impl DerefMut for PWindow {
295    fn deref_mut(&mut self) -> &mut Self::Target {
296        self.0.deref_mut()
297    }
298}
299
300unsafe impl Send for PWindow {}
301
302unsafe impl Sync for PWindow {}
303
304// these are technically already implemented, but somehow this fixed a error in wgpu
305#[cfg(feature = "raw-window-handle-v0-6")]
306impl HasWindowHandle for PWindow {
307    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
308        self.0.window_handle()
309    }
310}
311
312#[cfg(feature = "raw-window-handle-v0-6")]
313impl HasDisplayHandle for PWindow {
314    fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
315        self.0.display_handle()
316    }
317}
318
319/// Unique identifier for a `Window`.
320pub type WindowId = usize;
321
322#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
323#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
324pub struct Version {
325    pub major: u64,
326    pub minor: u64,
327    pub patch: u64,
328}
329
330/// Input actions.
331#[repr(i32)]
332#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
333#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
334pub enum Action {
335    Release = ffi::GLFW_RELEASE,
336    Press = ffi::GLFW_PRESS,
337    Repeat = ffi::GLFW_REPEAT,
338}
339
340/// Input keys.
341#[repr(i32)]
342#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
343#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
344pub enum Key {
345    Space = ffi::GLFW_KEY_SPACE,
346    Apostrophe = ffi::GLFW_KEY_APOSTROPHE,
347    Comma = ffi::GLFW_KEY_COMMA,
348    Minus = ffi::GLFW_KEY_MINUS,
349    Period = ffi::GLFW_KEY_PERIOD,
350    Slash = ffi::GLFW_KEY_SLASH,
351    Num0 = ffi::GLFW_KEY_0,
352    Num1 = ffi::GLFW_KEY_1,
353    Num2 = ffi::GLFW_KEY_2,
354    Num3 = ffi::GLFW_KEY_3,
355    Num4 = ffi::GLFW_KEY_4,
356    Num5 = ffi::GLFW_KEY_5,
357    Num6 = ffi::GLFW_KEY_6,
358    Num7 = ffi::GLFW_KEY_7,
359    Num8 = ffi::GLFW_KEY_8,
360    Num9 = ffi::GLFW_KEY_9,
361    Semicolon = ffi::GLFW_KEY_SEMICOLON,
362    Equal = ffi::GLFW_KEY_EQUAL,
363    A = ffi::GLFW_KEY_A,
364    B = ffi::GLFW_KEY_B,
365    C = ffi::GLFW_KEY_C,
366    D = ffi::GLFW_KEY_D,
367    E = ffi::GLFW_KEY_E,
368    F = ffi::GLFW_KEY_F,
369    G = ffi::GLFW_KEY_G,
370    H = ffi::GLFW_KEY_H,
371    I = ffi::GLFW_KEY_I,
372    J = ffi::GLFW_KEY_J,
373    K = ffi::GLFW_KEY_K,
374    L = ffi::GLFW_KEY_L,
375    M = ffi::GLFW_KEY_M,
376    N = ffi::GLFW_KEY_N,
377    O = ffi::GLFW_KEY_O,
378    P = ffi::GLFW_KEY_P,
379    Q = ffi::GLFW_KEY_Q,
380    R = ffi::GLFW_KEY_R,
381    S = ffi::GLFW_KEY_S,
382    T = ffi::GLFW_KEY_T,
383    U = ffi::GLFW_KEY_U,
384    V = ffi::GLFW_KEY_V,
385    W = ffi::GLFW_KEY_W,
386    X = ffi::GLFW_KEY_X,
387    Y = ffi::GLFW_KEY_Y,
388    Z = ffi::GLFW_KEY_Z,
389    LeftBracket = ffi::GLFW_KEY_LEFT_BRACKET,
390    Backslash = ffi::GLFW_KEY_BACKSLASH,
391    RightBracket = ffi::GLFW_KEY_RIGHT_BRACKET,
392    GraveAccent = ffi::GLFW_KEY_GRAVE_ACCENT,
393    World1 = ffi::GLFW_KEY_WORLD_1,
394    World2 = ffi::GLFW_KEY_WORLD_2,
395
396    Escape = ffi::GLFW_KEY_ESCAPE,
397    Enter = ffi::GLFW_KEY_ENTER,
398    Tab = ffi::GLFW_KEY_TAB,
399    Backspace = ffi::GLFW_KEY_BACKSPACE,
400    Insert = ffi::GLFW_KEY_INSERT,
401    Delete = ffi::GLFW_KEY_DELETE,
402    Right = ffi::GLFW_KEY_RIGHT,
403    Left = ffi::GLFW_KEY_LEFT,
404    Down = ffi::GLFW_KEY_DOWN,
405    Up = ffi::GLFW_KEY_UP,
406    PageUp = ffi::GLFW_KEY_PAGE_UP,
407    PageDown = ffi::GLFW_KEY_PAGE_DOWN,
408    Home = ffi::GLFW_KEY_HOME,
409    End = ffi::GLFW_KEY_END,
410    CapsLock = ffi::GLFW_KEY_CAPS_LOCK,
411    ScrollLock = ffi::GLFW_KEY_SCROLL_LOCK,
412    NumLock = ffi::GLFW_KEY_NUM_LOCK,
413    PrintScreen = ffi::GLFW_KEY_PRINT_SCREEN,
414    Pause = ffi::GLFW_KEY_PAUSE,
415    F1 = ffi::GLFW_KEY_F1,
416    F2 = ffi::GLFW_KEY_F2,
417    F3 = ffi::GLFW_KEY_F3,
418    F4 = ffi::GLFW_KEY_F4,
419    F5 = ffi::GLFW_KEY_F5,
420    F6 = ffi::GLFW_KEY_F6,
421    F7 = ffi::GLFW_KEY_F7,
422    F8 = ffi::GLFW_KEY_F8,
423    F9 = ffi::GLFW_KEY_F9,
424    F10 = ffi::GLFW_KEY_F10,
425    F11 = ffi::GLFW_KEY_F11,
426    F12 = ffi::GLFW_KEY_F12,
427    F13 = ffi::GLFW_KEY_F13,
428    F14 = ffi::GLFW_KEY_F14,
429    F15 = ffi::GLFW_KEY_F15,
430    F16 = ffi::GLFW_KEY_F16,
431    F17 = ffi::GLFW_KEY_F17,
432    F18 = ffi::GLFW_KEY_F18,
433    F19 = ffi::GLFW_KEY_F19,
434    F20 = ffi::GLFW_KEY_F20,
435    F21 = ffi::GLFW_KEY_F21,
436    F22 = ffi::GLFW_KEY_F22,
437    F23 = ffi::GLFW_KEY_F23,
438    F24 = ffi::GLFW_KEY_F24,
439    F25 = ffi::GLFW_KEY_F25,
440    Kp0 = ffi::GLFW_KEY_KP_0,
441    Kp1 = ffi::GLFW_KEY_KP_1,
442    Kp2 = ffi::GLFW_KEY_KP_2,
443    Kp3 = ffi::GLFW_KEY_KP_3,
444    Kp4 = ffi::GLFW_KEY_KP_4,
445    Kp5 = ffi::GLFW_KEY_KP_5,
446    Kp6 = ffi::GLFW_KEY_KP_6,
447    Kp7 = ffi::GLFW_KEY_KP_7,
448    Kp8 = ffi::GLFW_KEY_KP_8,
449    Kp9 = ffi::GLFW_KEY_KP_9,
450    KpDecimal = ffi::GLFW_KEY_KP_DECIMAL,
451    KpDivide = ffi::GLFW_KEY_KP_DIVIDE,
452    KpMultiply = ffi::GLFW_KEY_KP_MULTIPLY,
453    KpSubtract = ffi::GLFW_KEY_KP_SUBTRACT,
454    KpAdd = ffi::GLFW_KEY_KP_ADD,
455    KpEnter = ffi::GLFW_KEY_KP_ENTER,
456    KpEqual = ffi::GLFW_KEY_KP_EQUAL,
457    LeftShift = ffi::GLFW_KEY_LEFT_SHIFT,
458    LeftControl = ffi::GLFW_KEY_LEFT_CONTROL,
459    LeftAlt = ffi::GLFW_KEY_LEFT_ALT,
460    LeftSuper = ffi::GLFW_KEY_LEFT_SUPER,
461    RightShift = ffi::GLFW_KEY_RIGHT_SHIFT,
462    RightControl = ffi::GLFW_KEY_RIGHT_CONTROL,
463    RightAlt = ffi::GLFW_KEY_RIGHT_ALT,
464    RightSuper = ffi::GLFW_KEY_RIGHT_SUPER,
465    Menu = ffi::GLFW_KEY_MENU,
466    Unknown = ffi::GLFW_KEY_UNKNOWN,
467}
468
469/// Wrapper around `glfwGetKeyName`
470pub fn get_key_name(key: Option<Key>, scancode: Option<Scancode>) -> Option<String> {
471    unsafe {
472        string_from_nullable_c_str(ffi::glfwGetKeyName(
473            match key {
474                Some(k) => k as c_int,
475                None => ffi::GLFW_KEY_UNKNOWN,
476            },
477            scancode.unwrap_or(ffi::GLFW_KEY_UNKNOWN),
478        ))
479    }
480}
481
482/// Wrapper around `glfwGetKeyName`
483#[deprecated(
484    since = "0.16.0",
485    note = "'key_name' can cause a segfault, use 'get_key_name' instead"
486)]
487pub fn key_name(key: Option<Key>, scancode: Option<Scancode>) -> String {
488    unsafe {
489        string_from_c_str(ffi::glfwGetKeyName(
490            match key {
491                Some(k) => k as c_int,
492                None => ffi::GLFW_KEY_UNKNOWN,
493            },
494            scancode.unwrap_or(ffi::GLFW_KEY_UNKNOWN),
495        ))
496    }
497}
498
499/// Wrapper around `glfwGetKeyScancode`.
500pub fn get_key_scancode(key: Option<Key>) -> Option<Scancode> {
501    unsafe {
502        match ffi::glfwGetKeyScancode(match key {
503            Some(key) => key as c_int,
504            None => ffi::GLFW_KEY_UNKNOWN,
505        }) {
506            ffi::GLFW_KEY_UNKNOWN => None,
507            scancode => Some(scancode as Scancode),
508        }
509    }
510}
511
512impl Key {
513    /// Wrapper around `glfwGetKeyName` without scancode
514    #[deprecated(
515        since = "0.16.0",
516        note = "Key method 'name' can cause a segfault, use 'get_name' instead"
517    )]
518    pub fn name(&self) -> String {
519        #[allow(deprecated)]
520        key_name(Some(*self), None)
521    }
522
523    /// Wrapper around `glfwGetKeyName` without scancode
524    pub fn get_name(&self) -> Option<String> {
525        get_key_name(Some(*self), None)
526    }
527
528    /// Wrapper around `glfwGetKeyScancode`.
529    pub fn get_scancode(&self) -> Option<Scancode> {
530        get_key_scancode(Some(*self))
531    }
532}
533
534/// Mouse buttons. The `MouseButtonLeft`, `MouseButtonRight`, and
535/// `MouseButtonMiddle` aliases are supplied for convenience.
536#[repr(i32)]
537#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
538#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
539pub enum MouseButton {
540    /// The left mouse button. A `MouseButtonLeft` alias is provided to improve clarity.
541    Button1 = ffi::GLFW_MOUSE_BUTTON_1,
542    /// The right mouse button. A `MouseButtonRight` alias is provided to improve clarity.
543    Button2 = ffi::GLFW_MOUSE_BUTTON_2,
544    /// The middle mouse button. A `MouseButtonMiddle` alias is provided to improve clarity.
545    Button3 = ffi::GLFW_MOUSE_BUTTON_3,
546    Button4 = ffi::GLFW_MOUSE_BUTTON_4,
547    Button5 = ffi::GLFW_MOUSE_BUTTON_5,
548    Button6 = ffi::GLFW_MOUSE_BUTTON_6,
549    Button7 = ffi::GLFW_MOUSE_BUTTON_7,
550    Button8 = ffi::GLFW_MOUSE_BUTTON_8,
551}
552
553impl MouseButton {
554    /// Alias to `MouseButton1`, supplied for improved clarity.
555    pub const Left: Self = MouseButton::Button1;
556    /// Alias to `MouseButton2`, supplied for improved clarity.
557    pub const Right: Self = MouseButton::Button2;
558    /// Alias to `MouseButton3`, supplied for improved clarity.
559    pub const Middle: Self = MouseButton::Button3;
560
561    /// Converts from `i32`.
562    pub fn from_i32(n: i32) -> Option<MouseButton> {
563        if (0..=ffi::GLFW_MOUSE_BUTTON_LAST).contains(&n) {
564            Some(unsafe { mem::transmute(n) })
565        } else {
566            None
567        }
568    }
569}
570
571/// Formats the type using aliases rather than the default variant names.
572///
573/// # Example
574///
575/// ~~~ignore
576/// assert_eq(format!("{}", glfw::MouseButtonLeft), "MouseButton1");
577/// assert_eq(format!("{}", glfw::DebugAliases(glfw::MouseButtonLeft)), "MouseButtonLeft");
578/// ~~~
579pub struct DebugAliases<T>(pub T);
580
581impl fmt::Debug for DebugAliases<MouseButton> {
582    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583        let DebugAliases(button) = *self;
584        match button {
585            MouseButtonLeft => write!(f, "MouseButtonLeft"),
586            MouseButtonRight => write!(f, "MouseButtonRight"),
587            MouseButtonMiddle => write!(f, "MouseButtonMiddle"),
588            button => button.fmt(f),
589        }
590    }
591}
592
593/// Tokens corresponding to various error types.
594#[repr(i32)]
595#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
596#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
597pub enum Error {
598    NoError = ffi::GLFW_NO_ERROR,
599    NotInitialized = ffi::GLFW_NOT_INITIALIZED,
600    NoCurrentContext = ffi::GLFW_NO_CURRENT_CONTEXT,
601    InvalidEnum = ffi::GLFW_INVALID_ENUM,
602    InvalidValue = ffi::GLFW_INVALID_VALUE,
603    OutOfMemory = ffi::GLFW_OUT_OF_MEMORY,
604    ApiUnavailable = ffi::GLFW_API_UNAVAILABLE,
605    VersionUnavailable = ffi::GLFW_VERSION_UNAVAILABLE,
606    PlatformError = ffi::GLFW_PLATFORM_ERROR,
607    FormatUnavailable = ffi::GLFW_FORMAT_UNAVAILABLE,
608    NoWindowContext = ffi::GLFW_NO_WINDOW_CONTEXT,
609}
610
611impl fmt::Display for Error {
612    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613        let description = match *self {
614            Error::NoError => "NoError",
615            Error::NotInitialized => "NotInitialized",
616            Error::NoCurrentContext => "NoCurrentContext",
617            Error::InvalidEnum => "InvalidEnum",
618            Error::InvalidValue => "InvalidValue",
619            Error::OutOfMemory => "OutOfMemory",
620            Error::ApiUnavailable => "ApiUnavailable",
621            Error::VersionUnavailable => "VersionUnavailable",
622            Error::PlatformError => "PlatformError",
623            Error::FormatUnavailable => "FormatUnavailable",
624            Error::NoWindowContext => "NoWindowContext",
625        };
626
627        f.write_str(description)
628    }
629}
630
631impl error::Error for Error {}
632
633/// The function to be used with the `fail_on_errors!()` callback.
634pub fn fail_on_errors(e: Error, description: String) {
635    if e == Error::FormatUnavailable {
636        // https://github.com/PistonDevelopers/glfw-rs/issues/581
637        /*
638        This error only triggers on window creation and get_clipboard_string.
639        Both those function return None on erorr case, so, we can safely ignore this error.
640        */
641        return;
642    }
643    panic!("GLFW Error: {}", description);
644}
645
646/// A callback that triggers a task failure when an error is encountered.
647#[macro_export]
648macro_rules! fail_on_errors {
649    () => {{
650        |error, description| {
651            fail_on_errors(error, description);
652        }
653    }};
654}
655
656#[cfg(feature = "log")]
657/// The function to be used with the `LOG_ERRORS` callback.
658pub fn log_errors(_: Error, description: String) {
659    error!("GLFW Error: {}", description);
660}
661
662#[cfg(not(feature = "log"))]
663/// The function to be used with the `LOG_ERRORS` callback.
664pub fn log_errors(_: Error, description: String) {
665    eprintln!("GLFW Error: {}", description);
666}
667
668/// A callback that logs each error as it is encountered without triggering a
669/// task failure
670#[macro_export]
671macro_rules! log_errors {
672    () => {{
673        |error, description| {
674            log_errors(error, description);
675        }
676    }};
677}
678
679/// When not using the `image` library, or if you just want to,
680/// you can specify an image from its raw pixel data using this structure.
681#[derive(Debug)]
682pub struct PixelImage {
683    /// Width of the image in pixels
684    pub width: u32,
685    /// Height of the image in pixels
686    pub height: u32,
687    /// Pixels are 4 bytes each, one byte for each RGBA subpixel.
688    pub pixels: Vec<u32>,
689}
690
691/// Cursor modes.
692#[repr(i32)]
693#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
694#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
695pub enum CursorMode {
696    Normal = ffi::GLFW_CURSOR_NORMAL,
697    Hidden = ffi::GLFW_CURSOR_HIDDEN,
698    Disabled = ffi::GLFW_CURSOR_DISABLED,
699}
700
701/// Standard cursors provided by GLFW
702#[repr(i32)]
703#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
704#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
705pub enum StandardCursor {
706    /// The regular arrow cursor shape.
707    Arrow = ffi::GLFW_ARROW_CURSOR,
708    /// The text input I-beam cursor shape.
709    IBeam = ffi::GLFW_IBEAM_CURSOR,
710    /// The crosshair shape.
711    Crosshair = ffi::GLFW_CROSSHAIR_CURSOR,
712    /// The hand shape.
713    Hand = ffi::GLFW_HAND_CURSOR,
714    /// The horizontal resize arrow shape.
715    HResize = ffi::GLFW_HRESIZE_CURSOR,
716    /// The vertical resize arrow shape.
717    VResize = ffi::GLFW_VRESIZE_CURSOR,
718}
719
720/// Represents a window cursor that can be used to display any
721/// of the standard cursors or load a custom cursor from an image.
722///
723/// Note that the cursor object has a lifetime and will not display
724/// correctly after it has been dropped.
725#[derive(Debug)]
726pub struct Cursor {
727    ptr: *mut ffi::GLFWcursor,
728}
729
730impl Drop for Cursor {
731    fn drop(&mut self) {
732        unsafe { ffi::glfwDestroyCursor(self.ptr) }
733    }
734}
735
736impl Cursor {
737    /// Create a new cursor using `glfwCreateStandardCursor`
738    pub fn standard(cursor: StandardCursor) -> Cursor {
739        Cursor {
740            ptr: unsafe { ffi::glfwCreateStandardCursor(cursor as c_int) },
741        }
742    }
743
744    /// Creates a new cursor from the image provided via `glfwCreateCursor`
745    ///
746    /// Note that the cursor image will be the same size as the image provided,
747    /// so scaling it beforehand may be required.
748    ///
749    /// The cursor hotspot is specified in pixels, relative to the upper-left
750    /// corner of the cursor image. Like all other coordinate systems in GLFW,
751    /// the X-axis points to the right and the Y-axis points down.
752    #[cfg(feature = "image")]
753    pub fn create(image: image::RgbaImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
754        let (width, height) = image.dimensions();
755
756        let image_data = image.into_vec();
757
758        let glfw_image = ffi::GLFWimage {
759            width: width as c_int,
760            height: height as c_int,
761            pixels: image_data.as_ptr() as _,
762        };
763
764        Cursor {
765            ptr: unsafe {
766                ffi::glfwCreateCursor(
767                    &glfw_image as *const ffi::GLFWimage,
768                    x_hotspot as c_int,
769                    y_hotspot as c_int,
770                )
771            },
772        }
773    }
774
775    /// Creates a new cursor from the `PixelImage` provided via `glfwCreateCursor`
776    ///
777    /// Note that the cursor image will be the same size as the image provided,
778    /// so scaling it beforehand may be required.
779    ///
780    /// The cursor hotspot is specified in pixels, relative to the upper-left
781    /// corner of the cursor image. Like all other coordinate systems in GLFW,
782    /// the X-axis points to the right and the Y-axis points down.
783    pub fn create_from_pixels(image: PixelImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
784        let glfw_image = ffi::GLFWimage {
785            width: image.width as c_int,
786            height: image.height as c_int,
787            pixels: image.pixels.as_ptr() as _,
788        };
789
790        Cursor {
791            ptr: unsafe {
792                ffi::glfwCreateCursor(
793                    &glfw_image as *const ffi::GLFWimage,
794                    x_hotspot as c_int,
795                    y_hotspot as c_int,
796                )
797            },
798        }
799    }
800}
801
802/// Describes a single video mode.
803#[derive(Copy, Clone)]
804#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
805pub struct VidMode {
806    pub width: u32,
807    pub height: u32,
808    pub red_bits: u32,
809    pub green_bits: u32,
810    pub blue_bits: u32,
811    pub refresh_rate: u32,
812}
813
814/// Describes the gamma ramp of a monitor.
815#[derive(Debug)]
816#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
817pub struct GammaRamp {
818    pub red: Vec<c_ushort>,
819    pub green: Vec<c_ushort>,
820    pub blue: Vec<c_ushort>,
821}
822
823/// `ContextReleaseBehavior` specifies the release behavior to be used by the context.
824#[repr(i32)]
825#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
826#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
827pub enum ContextReleaseBehavior {
828    Any = ffi::GLFW_ANY_RELEASE_BEHAVIOR,
829    /// `Flush` tells the context to flush the pipeline whenever the context is released from being
830    /// the current one.
831    Flush = ffi::GLFW_RELEASE_BEHAVIOR_FLUSH,
832    /// `None` tells the context to NOT flush the pipeline on release
833    None = ffi::GLFW_RELEASE_BEHAVIOR_NONE,
834}
835
836/// Specifies the API to use to create the context
837#[repr(i32)]
838#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
839#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
840pub enum ContextCreationApi {
841    Native = ffi::GLFW_NATIVE_CONTEXT_API,
842    Egl = ffi::GLFW_EGL_CONTEXT_API,
843    OsMesa = ffi::GLFW_OSMESA_CONTEXT_API,
844}
845
846/// Specifies how the context should handle swapping the buffers.
847///
848/// i.e. the number of screen updates to wait from the time
849/// `glfwSwapBuffers`/`context.swap_buffers`
850/// was called before swapping the buffers and returning.
851#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
852#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
853pub enum SwapInterval {
854    /// Specifies no waits
855    None,
856    /// If either of the `WGL_EXT_swap_control_tear` and `GLX_EXT_swap_control_tear` extensions
857    /// are enabled, allows the adaptively swap the frame. Sometimes called Adaptive V-sync
858    Adaptive,
859    /// Synchronizes the buffers every N frames. Set to 1 for V-sync
860    Sync(u32),
861}
862
863/// An OpenGL process address.
864pub type GLProc = ffi::GLFWglproc;
865
866/// A Vulkan process address
867#[cfg(feature = "vulkan")]
868pub type VkProc = ffi::GLFWvkproc;
869
870/// Counts for (Calling glfwInit) - (Calling glfwTerminate)
871/// It uses for "global" refference counting for Glfw.
872static REF_COUNT_FOR_GLFW: AtomicUsize = AtomicUsize::new(0);
873
874/// A struct that represents a thread safe handle to a `Glfw`
875#[derive(Debug)]
876pub struct ThreadSafeGlfw {
877    glfw: Glfw,
878}
879
880impl ThreadSafeGlfw {
881    /// Creates a new `Glfw` wrapper that can be shared between threads
882    pub fn from(glfw: &mut Glfw) -> Self {
883        Self { glfw: glfw.clone() }
884    }
885
886    /// Wrapper function, please refer to [`Glfw::set_swap_interval`]
887    pub fn set_swap_interval(&mut self, interval: SwapInterval) {
888        self.glfw.set_swap_interval(interval);
889    }
890
891    /// Wrapper function, please refer to [`Glfw::extension_supported`]
892    pub fn extension_supported(&self, extension: &str) -> bool {
893        self.glfw.extension_supported(extension)
894    }
895
896    /// Wrapper function, please refer to [`Glfw::get_time`]
897    pub fn get_time(&self) -> f64 {
898        self.glfw.get_time()
899    }
900
901    /// Wrapper function, please refer to [`Glfw::set_time`]
902    pub fn set_time(&mut self, time: f64) {
903        self.glfw.set_time(time);
904    }
905
906    /// Wrapper function, please refer to [`Glfw::vulkan_supported`]
907    #[cfg(feature = "vulkan")]
908    pub fn vulkan_supported(&self) -> bool {
909        self.glfw.vulkan_supported()
910    }
911
912    /// Wrapper function, please refer to [`Glfw::get_required_instance_extensions`]
913    #[cfg(feature = "vulkan")]
914    pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
915        self.glfw.get_required_instance_extensions()
916    }
917
918    /// Wrapper function, please refer to [`Glfw::get_instance_proc_address_raw`]
919    #[cfg(feature = "vulkan")]
920    pub fn get_instance_proc_address_raw(
921        &self,
922        instance: ffi::VkInstance,
923        procname: &str,
924    ) -> VkProc {
925        self.glfw.get_instance_proc_address_raw(instance, procname)
926    }
927
928    /// Wrapper function, please refer to [`Glfw::get_physical_device_presentation_support_raw`]
929    #[cfg(feature = "vulkan")]
930    pub fn get_physical_device_presentation_support_raw(
931        &self,
932        instance: ffi::VkInstance,
933        device: ffi::VkPhysicalDevice,
934        queue_family: u32,
935    ) -> bool {
936        self.glfw
937            .get_physical_device_presentation_support_raw(instance, device, queue_family)
938    }
939
940    /// Wrapper function, please refer to [`Glfw::get_timer_value`]
941    pub fn get_timer_value(&self) -> u64 {
942        self.glfw.get_timer_value()
943    }
944
945    /// Wrapper function, please refer to [`Glfw::get_timer_frequency`]
946    pub fn get_timer_frequency(&self) -> u64 {
947        self.glfw.get_timer_frequency()
948    }
949
950    /// Wrapper function, please refer to [`Glfw::post_empty_event`]
951    pub fn post_empty_event(&self) {
952        self.glfw.post_empty_event()
953    }
954}
955
956unsafe impl Send for ThreadSafeGlfw {}
957
958/// A token from which to call various GLFW functions. It can be obtained by
959/// calling the `init` function. This cannot be sent to other tasks, and should
960/// only be initialized on the main platform thread. Whilst this might make
961/// performing some operations harder, this is to ensure thread safety is enforced
962/// statically.
963#[non_exhaustive]
964#[derive(Debug)]
965pub struct Glfw {
966    phantom: std::marker::PhantomData<*const ()>,
967}
968
969/// An error that might be returned when `glfw::init` is called.
970#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
971#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
972pub enum InitError {
973    /// Deprecated. Does not occur.
974    AlreadyInitialized,
975    /// An internal error occurred when trying to initialize the library.
976    Internal,
977}
978
979impl fmt::Display for InitError {
980    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981        let description = match *self {
982            InitError::AlreadyInitialized => "Already Initialized",
983            InitError::Internal => "Internal Initialization Error",
984        };
985
986        f.write_str(description)
987    }
988}
989
990impl error::Error for InitError {}
991
992/// Initialization hints that can be set using the `init_hint` function.
993#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
994#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
995pub enum InitHint {
996    Platform(Platform),
997    /// Specifies whether to also expose joystick hats as buttons, for compatibility with earlier
998    /// versions of GLFW that did not have `glfwGetJoystickHats`.
999    JoystickHatButtons(bool),
1000    /// Specifies whether to set the current directory to the application to the
1001    /// `Contents/Resources` subdirectory of the application's bundle, if present.
1002    ///
1003    /// This is ignored on platforms besides macOS.
1004    CocoaChdirResources(bool),
1005    /// Specifies whether to create a basic menu bar, either from a nib or manually, when the first
1006    /// window is created, which is when AppKit is initialized.
1007    ///
1008    /// This is ignored on platforms besides macOS.
1009    CocoaMenubar(bool),
1010}
1011
1012/// The platform to use when initializing GLFW.
1013/// see [InitHint::Platform]
1014///
1015/// To check if a particular platform is supported, use [`Platform::is_supported`]
1016#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
1017#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1018#[repr(i32)]
1019pub enum Platform {
1020    X11 = ffi::GLFW_PLATFORM_X11,
1021    Wayland = ffi::GLFW_PLATFORM_WAYLAND,
1022    Win32 = ffi::GLFW_PLATFORM_WIN32,
1023    MacOS = ffi::GLFW_PLATFORM_COCOA,
1024    /// Useful for testing.
1025    Null = ffi::GLFW_PLATFORM_NULL,
1026    /// Chooses the best available platform.
1027    Any = ffi::GLFW_ANY_PLATFORM,
1028}
1029impl Platform {
1030    /// Whether this platform is supported.
1031    pub fn is_supported(&self) -> bool {
1032        unsafe { ffi::glfwPlatformSupported(*self as c_int) == ffi::GLFW_TRUE }
1033    }
1034}
1035/// Sets hints for the next initialization of GLFW.
1036///
1037/// The values you set hints to are never reset by GLFW, but they only take effect during
1038/// initialization. Once GLFW has been initialized, any values you set will be ignored until the
1039/// library is terminated and initialized again.
1040///
1041/// Wrapper for `glfwInitHint`.
1042pub fn init_hint(hint: InitHint) {
1043    match hint {
1044        InitHint::Platform(platform) => unsafe {
1045            ffi::glfwInitHint(ffi::GLFW_PLATFORM, platform as c_int)
1046        },
1047        InitHint::JoystickHatButtons(joystick_hat_buttons) => unsafe {
1048            ffi::glfwInitHint(
1049                ffi::GLFW_JOYSTICK_HAT_BUTTONS,
1050                joystick_hat_buttons as c_int,
1051            )
1052        },
1053        InitHint::CocoaChdirResources(chdir) => unsafe {
1054            ffi::glfwInitHint(ffi::GLFW_COCOA_CHDIR_RESOURCES, chdir as c_int)
1055        },
1056        InitHint::CocoaMenubar(menubar) => unsafe {
1057            ffi::glfwInitHint(ffi::GLFW_COCOA_MENUBAR, menubar as c_int)
1058        },
1059    }
1060}
1061/// Initializes the GLFW library. This must be called on the main platform
1062/// thread.
1063///
1064/// Wrapper for `glfwInit`.
1065///
1066/// # Example
1067///
1068/// ~~~no_run
1069/// extern crate glfw;
1070///
1071/// fn main() {
1072///    let glfw = glfw::init_no_callbacks().unwrap();
1073/// }
1074/// ~~~
1075///
1076/// # Error callback
1077///
1078/// An error callback can be set if desired. This allows for the handling of any
1079/// errors that occur during initialization. This can subsequently be changed
1080/// using the `glfw::init` function.
1081///
1082/// ~~~no_run
1083/// extern crate glfw;
1084/// #[macro_use]
1085/// extern crate log;
1086///
1087/// fn main() {
1088///    let glfw = glfw::init(error_callback).unwrap();
1089/// }
1090///
1091/// fn error_callback(err: glfw::Error, description: String) {
1092///     error!("GLFW error {:?}: {:?}", err, description);
1093/// }
1094/// ~~~
1095///
1096/// # Returns
1097///
1098/// - If initialization was successful a `Glfw` token will be returned along with a `Receiver` from
1099///   which errors can be intercepted.
1100/// - Subsequent calls to `init` will return `Glfw` token immediately.
1101/// - If an initialization error occurred within the GLFW library `Err(InternalInitError)` will be
1102///   returned.
1103pub fn init<T>(callback: T) -> Result<Glfw, InitError>
1104where
1105    T: FnMut(Error, String) + 'static,
1106{
1107    // Initialize the error callback. This is done
1108    // before `ffi::glfwInit` because errors could occur during
1109    // initialization.
1110    callbacks::error::set(callback);
1111
1112    init_no_callbacks()
1113}
1114
1115pub fn init_no_callbacks() -> Result<Glfw, InitError> {
1116    // initialize GLFW.
1117    // FYI: multiple not terminated ffi::glfwInit() returns ffi::GLFW_TRUE immediately.
1118    // https://www.glfw.org/docs/latest/group__init.html#ga317aac130a235ab08c6db0834907d85e
1119    if unsafe { ffi::glfwInit() } == ffi::GLFW_TRUE {
1120        REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
1121        Ok(Glfw {
1122            phantom: std::marker::PhantomData,
1123        })
1124    } else {
1125        Err(InitError::Internal)
1126    }
1127}
1128
1129impl Glfw {
1130    /// Sets the error callback, overwriting the previous one stored.
1131    ///
1132    /// # Example
1133    ///
1134    /// ~~~ignore
1135    /// // sets a new callback
1136    /// let mut error_count: usize = 0;
1137    /// glfw.set_error_callback(Some(move |error, description| {
1138    ///     println!("GLFW error {}: {}", error_count, description);
1139    ///     error_count += 1;
1140    /// }));
1141    ///
1142    /// // removes the previously set callback
1143    /// glfw.set_error_callback(None);
1144    /// ~~~
1145    ///
1146    /// The `fail_on_errors!()` and `log_errors!()` callback macros are provided for
1147    /// convenience. For example:
1148    ///
1149    /// ~~~ignore
1150    /// // triggers a task failure when a GLFW error is encountered.
1151    /// glfw.set_error_callback(fail_on_errors!());
1152    /// ~~~
1153    pub fn set_error_callback<T>(&mut self, callback: T)
1154    where
1155        T: FnMut(Error, String) + 'static,
1156    {
1157        callbacks::error::set(callback);
1158    }
1159
1160    /// Unsets the monitor callback
1161    pub fn unset_error_callback(&mut self) {
1162        callbacks::error::unset();
1163    }
1164
1165    /// Sets the monitor callback, overwriting the previous one stored.
1166    pub fn set_monitor_callback<T>(&mut self, callback: T)
1167    where
1168        T: FnMut(Monitor, MonitorEvent) + 'static,
1169    {
1170        callbacks::monitor::set(callback);
1171    }
1172
1173    /// Unsets the monitor callback
1174    pub fn unset_monitor_callback(&mut self) {
1175        callbacks::monitor::unset();
1176    }
1177
1178    /// Sets the joystick callback, overwriting the previous one stored
1179    pub fn set_joystick_callback<T>(&mut self, callback: T)
1180    where
1181        T: FnMut(JoystickId, JoystickEvent) + 'static,
1182    {
1183        callbacks::joystick::set(callback);
1184    }
1185
1186    /// Unsets the joystick callback
1187    pub fn unset_joystick_callback(&mut self) {
1188        callbacks::joystick::unset();
1189    }
1190
1191    /// Supplies the primary monitor to the closure provided, if it exists.
1192    /// This is usually the monitor where elements like the Windows task bar or
1193    /// the OS X menu bar is located.
1194    ///
1195    /// # Example
1196    ///
1197    /// ~~~ignore
1198    /// let (window, events) = glfw.with_primary_monitor(|_, m| {
1199    ///     glfw.create_window(300, 300, "Hello this is window",
1200    ///         m.map_or(glfw::WindowMode::Windowed, |m| glfw::FullScreen(m)))
1201    /// }).expect("Failed to create GLFW window.");
1202    /// ~~~
1203    pub fn with_primary_monitor<T, F>(&mut self, f: F) -> T
1204    where
1205        F: FnOnce(&mut Self, Option<&mut Monitor>) -> T,
1206    {
1207        match unsafe { ffi::glfwGetPrimaryMonitor() } {
1208            ptr if ptr.is_null() => f(self, None),
1209            ptr => f(self, Some(&mut Monitor { ptr })),
1210        }
1211    }
1212
1213    /// Supplies the window monitor to the closure provided, if it's fullscreen.
1214    ///
1215    /// # Example
1216    ///
1217    /// ~~~ignore
1218    /// let (window, events) = glfw.with_window_monitor(|_, m| {
1219    ///     glfw.create_window(300, 300, "Hello this is window",
1220    ///         m.map_or(glfw::WindowMode::Windowed, |m| glfw::FullScreen(m)))
1221    /// }).expect("Failed to create GLFW window.");
1222    /// ~~~
1223    pub fn with_window_monitor<T, F>(&mut self, window: &mut Window, f: F) -> T
1224    where
1225        F: FnOnce(&mut Self, Option<&mut Monitor>) -> T,
1226    {
1227        match unsafe { ffi::glfwGetWindowMonitor(window.ptr) } {
1228            ptr if ptr.is_null() => f(self, None),
1229            ptr => f(self, Some(&mut Monitor { ptr })),
1230        }
1231    }
1232
1233    /// Supplies a vector of the currently connected monitors to the closure
1234    /// provided.
1235    ///
1236    /// # Example
1237    ///
1238    /// ~~~ignore
1239    /// glfw.with_connected_monitors(|_, monitors| {
1240    ///     for monitor in monitors.iter() {
1241    ///         println!("{}: {}", monitor.get_name(), monitor.get_video_mode());
1242    ///     }
1243    /// });
1244    /// ~~~
1245    pub fn with_connected_monitors<T, F>(&mut self, f: F) -> T
1246    where
1247        F: FnOnce(&mut Self, &[&mut Monitor]) -> T,
1248    {
1249        unsafe {
1250            let mut count = 0;
1251            let ptr = ffi::glfwGetMonitors(&mut count);
1252            let mut monitors = slice::from_raw_parts(ptr as *const _, count as usize)
1253                .iter()
1254                .map(|&ptr| Monitor { ptr })
1255                .collect::<Vec<Monitor>>();
1256
1257            let refs: Vec<&mut Monitor> = monitors.iter_mut().collect();
1258            f(self, &refs)
1259        }
1260    }
1261
1262    /// Queries Vulkan support via `glfwVulkanSupported`
1263    #[cfg(feature = "vulkan")]
1264    pub fn vulkan_supported(&self) -> bool {
1265        unsafe { ffi::glfwVulkanSupported() == ffi::GLFW_TRUE }
1266    }
1267
1268    /// This is used to set the window hints for the next call to
1269    /// `Glfw::create_window`. The hints can be reset to their default values
1270    /// using calling the `Glfw::default_window_hints` function.
1271    ///
1272    /// Wrapper for `glfwWindowHint`
1273    ///
1274    /// # OpenGL 3.x and 4.x on Mac OS X
1275    ///
1276    /// The only OpenGL 3.x and 4.x contexts supported by OS X are
1277    /// forward-compatible, core profile contexts.
1278    ///
1279    /// 10.7 and 10.8 support the following OpenGL versions:
1280    ///
1281    /// - `glfw::WindowHint::ContextVersion(3, 2)`
1282    ///
1283    /// 10.9 supports the following OpenGL versions
1284    ///
1285    /// - `glfw::WindowHint::ContextVersion(3, 2)`
1286    /// - `glfw::WindowHint::ContextVersion(3, 3)`
1287    /// - `glfw::WindowHint::ContextVersion(4, 1)`
1288    ///
1289    /// To create an OS X compatible context, the hints should be specified as
1290    /// follows:
1291    ///
1292    /// ~~~ignore
1293    /// glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
1294    /// glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
1295    /// glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
1296    /// ~~~
1297    pub fn window_hint(&mut self, hint: WindowHint) {
1298        //This is just a simple function to unwrap the option and convert it to `c_int` or use
1299        // `GLFW_DONT_CARE`, then call `glfwWindowHint` with the result. It was required because
1300        // `GLFW_DONT_CARE` is signed, so `value.unwrap_or(ffi::GLFW_DONT_CARE)` wouldn't work because
1301        // of the type difference.
1302        #[inline(always)]
1303        unsafe fn dont_care_hint(hint: c_int, value: Option<u32>) {
1304            ffi::glfwWindowHint(hint, unwrap_dont_care(value))
1305        }
1306
1307        #[inline(always)]
1308        unsafe fn string_hint(hint: c_int, value: Option<String>) {
1309            let value = if let Some(value) = &value {
1310                value.as_str()
1311            } else {
1312                ""
1313            };
1314            with_c_str(value, |value| ffi::glfwWindowHintString(hint, value))
1315        }
1316
1317        match hint {
1318            WindowHint::MousePassthrough(value) => unsafe {
1319                ffi::glfwWindowHint(ffi::GLFW_MOUSE_PASSTHROUGH, value as c_int)
1320            },
1321            WindowHint::RedBits(bits) => unsafe { dont_care_hint(ffi::GLFW_RED_BITS, bits) },
1322            WindowHint::GreenBits(bits) => unsafe { dont_care_hint(ffi::GLFW_GREEN_BITS, bits) },
1323            WindowHint::BlueBits(bits) => unsafe { dont_care_hint(ffi::GLFW_BLUE_BITS, bits) },
1324            WindowHint::AlphaBits(bits) => unsafe { dont_care_hint(ffi::GLFW_ALPHA_BITS, bits) },
1325            WindowHint::DepthBits(bits) => unsafe { dont_care_hint(ffi::GLFW_DEPTH_BITS, bits) },
1326            WindowHint::StencilBits(bits) => unsafe {
1327                dont_care_hint(ffi::GLFW_STENCIL_BITS, bits)
1328            },
1329            WindowHint::AccumRedBits(bits) => unsafe {
1330                dont_care_hint(ffi::GLFW_ACCUM_RED_BITS, bits)
1331            },
1332            WindowHint::AccumGreenBits(bits) => unsafe {
1333                dont_care_hint(ffi::GLFW_ACCUM_GREEN_BITS, bits)
1334            },
1335            WindowHint::AccumBlueBits(bits) => unsafe {
1336                dont_care_hint(ffi::GLFW_ACCUM_BLUE_BITS, bits)
1337            },
1338            WindowHint::AccumAlphaBits(bits) => unsafe {
1339                dont_care_hint(ffi::GLFW_ACCUM_ALPHA_BITS, bits)
1340            },
1341            WindowHint::AuxBuffers(num_buffers) => unsafe {
1342                dont_care_hint(ffi::GLFW_AUX_BUFFERS, num_buffers)
1343            },
1344            WindowHint::Samples(num_samples) => unsafe {
1345                dont_care_hint(ffi::GLFW_SAMPLES, num_samples)
1346            },
1347            WindowHint::RefreshRate(rate) => unsafe {
1348                dont_care_hint(ffi::GLFW_REFRESH_RATE, rate)
1349            },
1350            WindowHint::Stereo(is_stereo) => unsafe {
1351                ffi::glfwWindowHint(ffi::GLFW_STEREO, is_stereo as c_int)
1352            },
1353            WindowHint::SRgbCapable(is_capable) => unsafe {
1354                ffi::glfwWindowHint(ffi::GLFW_SRGB_CAPABLE, is_capable as c_int)
1355            },
1356            WindowHint::ClientApi(api) => unsafe {
1357                ffi::glfwWindowHint(ffi::GLFW_CLIENT_API, api as c_int)
1358            },
1359            WindowHint::ContextVersionMajor(major) => unsafe {
1360                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MAJOR, major as c_int)
1361            },
1362            WindowHint::ContextVersionMinor(minor) => unsafe {
1363                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MINOR, minor as c_int)
1364            },
1365            WindowHint::ContextVersion(major, minor) => unsafe {
1366                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MAJOR, major as c_int);
1367                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MINOR, minor as c_int)
1368            },
1369            WindowHint::ContextRobustness(robustness) => unsafe {
1370                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_ROBUSTNESS, robustness as c_int)
1371            },
1372            WindowHint::OpenGlForwardCompat(is_compat) => unsafe {
1373                ffi::glfwWindowHint(ffi::GLFW_OPENGL_FORWARD_COMPAT, is_compat as c_int)
1374            },
1375            WindowHint::OpenGlDebugContext(is_debug) => unsafe {
1376                ffi::glfwWindowHint(ffi::GLFW_OPENGL_DEBUG_CONTEXT, is_debug as c_int)
1377            },
1378            WindowHint::OpenGlProfile(profile) => unsafe {
1379                ffi::glfwWindowHint(ffi::GLFW_OPENGL_PROFILE, profile as c_int)
1380            },
1381            WindowHint::Resizable(is_resizable) => unsafe {
1382                ffi::glfwWindowHint(ffi::GLFW_RESIZABLE, is_resizable as c_int)
1383            },
1384            WindowHint::Visible(is_visible) => unsafe {
1385                ffi::glfwWindowHint(ffi::GLFW_VISIBLE, is_visible as c_int)
1386            },
1387            WindowHint::Decorated(is_decorated) => unsafe {
1388                ffi::glfwWindowHint(ffi::GLFW_DECORATED, is_decorated as c_int)
1389            },
1390            WindowHint::AutoIconify(auto_iconify) => unsafe {
1391                ffi::glfwWindowHint(ffi::GLFW_AUTO_ICONIFY, auto_iconify as c_int)
1392            },
1393            WindowHint::Floating(is_floating) => unsafe {
1394                ffi::glfwWindowHint(ffi::GLFW_FLOATING, is_floating as c_int)
1395            },
1396            WindowHint::Focused(is_focused) => unsafe {
1397                ffi::glfwWindowHint(ffi::GLFW_FOCUSED, is_focused as c_int)
1398            },
1399            WindowHint::Maximized(is_maximized) => unsafe {
1400                ffi::glfwWindowHint(ffi::GLFW_MAXIMIZED, is_maximized as c_int)
1401            },
1402            WindowHint::ContextNoError(is_no_error) => unsafe {
1403                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_NO_ERROR, is_no_error as c_int)
1404            },
1405            WindowHint::ContextCreationApi(api) => unsafe {
1406                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_CREATION_API, api as c_int)
1407            },
1408            WindowHint::ContextReleaseBehavior(behavior) => unsafe {
1409                ffi::glfwWindowHint(ffi::GLFW_CONTEXT_RELEASE_BEHAVIOR, behavior as c_int)
1410            },
1411            WindowHint::DoubleBuffer(is_dbuffered) => unsafe {
1412                ffi::glfwWindowHint(ffi::GLFW_DOUBLEBUFFER, is_dbuffered as c_int)
1413            },
1414            WindowHint::CenterCursor(center_cursor) => unsafe {
1415                ffi::glfwWindowHint(ffi::GLFW_CENTER_CURSOR, center_cursor as c_int)
1416            },
1417            WindowHint::TransparentFramebuffer(is_transparent) => unsafe {
1418                ffi::glfwWindowHint(ffi::GLFW_TRANSPARENT_FRAMEBUFFER, is_transparent as c_int)
1419            },
1420            WindowHint::FocusOnShow(focus) => unsafe {
1421                ffi::glfwWindowHint(ffi::GLFW_FOCUS_ON_SHOW, focus as c_int)
1422            },
1423            WindowHint::ScaleToMonitor(scale) => unsafe {
1424                ffi::glfwWindowHint(ffi::GLFW_SCALE_TO_MONITOR, scale as c_int)
1425            },
1426            WindowHint::CocoaRetinaFramebuffer(retina_fb) => unsafe {
1427                ffi::glfwWindowHint(ffi::GLFW_COCOA_RETINA_FRAMEBUFFER, retina_fb as c_int)
1428            },
1429            WindowHint::CocoaFrameName(name) => unsafe {
1430                string_hint(ffi::GLFW_COCOA_FRAME_NAME, name)
1431            },
1432            WindowHint::CocoaGraphicsSwitching(graphics_switching) => unsafe {
1433                ffi::glfwWindowHint(
1434                    ffi::GLFW_COCOA_GRAPHICS_SWITCHING,
1435                    graphics_switching as c_int,
1436                )
1437            },
1438            WindowHint::X11ClassName(class_name) => unsafe {
1439                string_hint(ffi::GLFW_X11_CLASS_NAME, class_name)
1440            },
1441            WindowHint::X11InstanceName(instance_name) => unsafe {
1442                string_hint(ffi::GLFW_X11_INSTANCE_NAME, instance_name)
1443            },
1444        }
1445    }
1446
1447    /// Resets the window hints previously set by the `window_hint` function to
1448    /// their default values.
1449    ///
1450    /// Wrapper for `glfwDefaultWindowHints`.
1451    pub fn default_window_hints(&mut self) {
1452        unsafe {
1453            ffi::glfwDefaultWindowHints();
1454        }
1455    }
1456
1457    /// Creates a new window.
1458    ///
1459    /// Wrapper for `glfwCreateWindow`.
1460    pub fn create_window(
1461        &mut self,
1462        width: u32,
1463        height: u32,
1464        title: &str,
1465        mode: WindowMode<'_>,
1466    ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
1467        #[cfg(feature = "wayland")]
1468        {
1469            // Has to be set otherwise wayland refuses to open window.
1470            self.window_hint(WindowHint::Focused(false));
1471        }
1472        self.create_window_intern(width, height, title, mode, None)
1473    }
1474
1475    /// Internal wrapper for `glfwCreateWindow`.
1476    fn create_window_intern(
1477        &self,
1478        width: u32,
1479        height: u32,
1480        title: &str,
1481        mode: WindowMode<'_>,
1482        share: Option<&Window>,
1483    ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
1484        let ptr = unsafe {
1485            with_c_str(title, |title| {
1486                ffi::glfwCreateWindow(
1487                    width as c_int,
1488                    height as c_int,
1489                    title,
1490                    mode.to_ptr(),
1491                    match share {
1492                        Some(w) => w.ptr,
1493                        None => ptr::null_mut(),
1494                    },
1495                )
1496            })
1497        };
1498        if ptr.is_null() {
1499            None
1500        } else {
1501            let (drop_sender, drop_receiver) = channel();
1502            let (sender, receiver) = glfw_channel(16, 256);
1503            let window = Window {
1504                ptr,
1505                glfw: self.clone(),
1506                is_shared: share.is_some(),
1507                drop_sender: Some(drop_sender),
1508                drop_receiver,
1509                current_cursor: None,
1510            };
1511            let mut callbacks = Box::new(WindowCallbacks::new(sender));
1512            let mut window = PWindow(Box::new(window));
1513
1514            unsafe {
1515                callbacks.window_ptr = window.raw_ptr();
1516                ffi::glfwSetWindowUserPointer(ptr, mem::transmute(callbacks));
1517            }
1518
1519            Some((window, receiver))
1520        }
1521    }
1522
1523    /// Makes the context of the specified window current. If no window is given
1524    /// then the current context is detached.
1525    ///
1526    /// Wrapper for `glfwMakeContextCurrent`.
1527    pub fn make_context_current(&mut self, context: Option<&Window>) {
1528        match context {
1529            Some(window) => unsafe { ffi::glfwMakeContextCurrent(window.ptr) },
1530            None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
1531        }
1532    }
1533
1534    /// Wrapper for `glfwGetX11Display`
1535    #[cfg(all(not(target_os = "windows"), not(target_os = "macos"), feature = "x11"))]
1536    pub fn get_x11_display(&self) -> *mut c_void {
1537        unsafe { ffi::glfwGetX11Display() }
1538    }
1539
1540    /// Wrapper for `glfwGetWaylandDisplay`
1541    #[cfg(all(
1542        not(target_os = "windows"),
1543        not(target_os = "macos"),
1544        feature = "wayland"
1545    ))]
1546    pub fn get_wayland_display(&self) -> *mut c_void {
1547        unsafe { ffi::glfwGetWaylandDisplay().cast_mut() }
1548    }
1549    /// Wrapper for `glfwGetPlatform`
1550    pub fn get_platform(&self) -> Platform {
1551        unsafe { mem::transmute(ffi::glfwGetPlatform()) }
1552    }
1553    /// Immediately process the received events.
1554    ///
1555    /// Wrapper for `glfwPollEvents`.
1556    pub fn poll_events(&mut self) {
1557        unsafe {
1558            ffi::glfwPollEvents();
1559        }
1560    }
1561
1562    /// Immediately process the received events. The *unbuffered* variant differs by allowing
1563    /// inspection of events *prior* to their associated native callback returning. This also
1564    /// provides a way to synchronously respond to the event. Events returned by the closure
1565    /// are delivered to the channel receiver just as if `poll_events` was called. Returning
1566    /// `None` from the closure will drop the event.
1567    ///
1568    /// Wrapper for `glfwPollEvents`.
1569    pub fn poll_events_unbuffered<F>(&mut self, mut f: F)
1570    where
1571        F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1572    {
1573        let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1574        self.poll_events();
1575    }
1576
1577    /// Sleep until at least one event has been received, and then perform the
1578    /// equivalent of `Glfw::poll_events`.
1579    ///
1580    /// Wrapper for `glfwWaitEvents`.
1581    pub fn wait_events(&mut self) {
1582        unsafe {
1583            ffi::glfwWaitEvents();
1584        }
1585    }
1586
1587    /// Sleep until at least one event has been received, and then perform the
1588    /// equivalent of `Glfw::poll_events_unbuffered`.
1589    ///
1590    /// Wrapper for `glfwWaitEvents`.
1591    pub fn wait_events_unbuffered<F>(&mut self, mut f: F)
1592    where
1593        F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1594    {
1595        let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1596        self.wait_events();
1597    }
1598
1599    /// Sleep until at least one event has been received, or until the specified
1600    /// timeout is reached, and then perform the equivalent of `Glfw::poll_events`.
1601    /// Timeout is specified in seconds.
1602    ///
1603    /// Wrapper for `glfwWaitEventsTimeout`.
1604    pub fn wait_events_timeout(&mut self, timeout: f64) {
1605        unsafe {
1606            ffi::glfwWaitEventsTimeout(timeout);
1607        }
1608    }
1609
1610    /// Sleep until at least one event has been received, or until the specified
1611    /// timeout is reached, and then perform the equivalent of `Glfw::poll_events_unbuffered`.
1612    /// Timeout is specified in seconds.
1613    ///
1614    /// Wrapper for `glfwWaitEventsTimeout`.
1615    pub fn wait_events_timeout_unbuffered<F>(&mut self, timeout: f64, mut f: F)
1616    where
1617        F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1618    {
1619        let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1620        self.wait_events_timeout(timeout);
1621    }
1622
1623    /// Posts an empty event from the current thread to the event queue, causing
1624    /// `wait_events` or `wait_events_timeout` to return.
1625    /// If no windows exist, this function returns immediately.
1626    ///
1627    /// Wrapper for `glfwPostEmptyEvent`.
1628    pub fn post_empty_event(&self) {
1629        unsafe {
1630            ffi::glfwPostEmptyEvent();
1631        }
1632    }
1633
1634    /// Returns the current value of the GLFW timer. Unless the timer has been
1635    /// set using `glfw::set_time`, the timer measures time elapsed since GLFW
1636    /// was initialized.
1637    ///
1638    /// Wrapper for `glfwGetTime`.
1639    pub fn get_time(&self) -> f64 {
1640        unsafe { ffi::glfwGetTime() as f64 }
1641    }
1642
1643    /// Sets the value of the GLFW timer.
1644    ///
1645    /// Wrapper for `glfwSetTime`.
1646    pub fn set_time(&mut self, time: f64) {
1647        unsafe {
1648            ffi::glfwSetTime(time as c_double);
1649        }
1650    }
1651
1652    /// Wrapper for `glfwGetTimerValue`.
1653    pub fn get_timer_value(&self) -> u64 {
1654        unsafe { ffi::glfwGetTimerValue() as u64 }
1655    }
1656
1657    /// Wrapper for `glfwGetTimerFrequency`
1658    pub fn get_timer_frequency(&self) -> u64 {
1659        unsafe { ffi::glfwGetTimerFrequency() as u64 }
1660    }
1661
1662    /// Sets the number of screen updates to wait before swapping the buffers of
1663    /// the current context and returning from `Window::swap_buffers`.
1664    ///
1665    /// Wrapper for `glfwSwapInterval`.
1666    pub fn set_swap_interval(&mut self, interval: SwapInterval) {
1667        unsafe {
1668            ffi::glfwSwapInterval(match interval {
1669                SwapInterval::None => 0_i32,
1670                SwapInterval::Adaptive => -1_i32,
1671                SwapInterval::Sync(interval) => interval as c_int,
1672            })
1673        }
1674    }
1675
1676    /// Returns `true` if the specified OpenGL or context creation API extension
1677    /// is supported by the current context.
1678    ///
1679    /// Wrapper for `glfwExtensionSupported`.
1680    pub fn extension_supported(&self, extension: &str) -> bool {
1681        unsafe {
1682            with_c_str(extension, |extension| {
1683                ffi::glfwExtensionSupported(extension) == ffi::GLFW_TRUE
1684            })
1685        }
1686    }
1687
1688    /// Wrapper for `glfwGetRequiredInstanceExtensions`
1689    ///
1690    /// This function returns a Vector of names of Vulkan instance extensions
1691    /// required by GLFW for creating Vulkan surfaces for GLFW windows. If successful,
1692    /// the list will always contains `VK_KHR_surface`, so if you don't require any
1693    /// additional extensions you can pass this list directly to the `VkInstanceCreateInfo` struct.
1694    ///
1695    /// Will return `None` if the API is unavailable.
1696    #[cfg(feature = "vulkan")]
1697    pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
1698        let mut len: c_uint = 0;
1699
1700        unsafe {
1701            let raw_extensions: *const *const c_char =
1702                ffi::glfwGetRequiredInstanceExtensions(&mut len as *mut c_uint);
1703
1704            if !raw_extensions.is_null() {
1705                return Some(
1706                    slice::from_raw_parts(raw_extensions, len as usize)
1707                        .iter()
1708                        .map(|extensions| string_from_c_str(*extensions))
1709                        .collect(),
1710                );
1711            }
1712        }
1713
1714        None
1715    }
1716
1717    /// Returns the address of the specified client API or extension function if
1718    /// it is supported by the current context, NULL otherwise.
1719    ///
1720    /// Wrapper for `glfwGetProcAddress`.
1721    pub fn get_proc_address_raw(&self, procname: &str) -> GLProc {
1722        debug_assert!(unsafe { ffi::glfwGetCurrentContext() } != std::ptr::null_mut());
1723        with_c_str(procname, |procname| unsafe {
1724            ffi::glfwGetProcAddress(procname)
1725        })
1726    }
1727
1728    /// This function returns the address of the specified Vulkan core or extension function
1729    /// for the specified instance. If instance is set to NULL it can return any function
1730    /// exported from the Vulkan loader, including at least the following functions:
1731    ///
1732    /// * `vkEnumerateInstanceExtensionProperties`
1733    /// * `vkEnumerateInstanceLayerProperties`
1734    /// * `vkCreateInstance`
1735    /// * `vkGetInstanceProcAddr`
1736    ///
1737    /// If Vulkan is not available on the machine, this function returns `NULL`
1738    ///
1739    /// Wrapper for `glfwGetInstanceProcAddress`
1740    #[cfg(feature = "vulkan")]
1741    pub fn get_instance_proc_address_raw(
1742        &self,
1743        instance: ffi::VkInstance,
1744        procname: &str,
1745    ) -> VkProc {
1746        with_c_str(procname, |procname| unsafe {
1747            ffi::glfwGetInstanceProcAddress(instance, procname)
1748        })
1749    }
1750
1751    /// This function returns whether the specified queue family of the specified
1752    /// physical device supports presentation to the platform GLFW was built for.
1753    ///
1754    /// Wrapper for `glfwGetPhysicalDevicePresentationSupport`
1755    #[cfg(feature = "vulkan")]
1756    pub fn get_physical_device_presentation_support_raw(
1757        &self,
1758        instance: ffi::VkInstance,
1759        device: ffi::VkPhysicalDevice,
1760        queue_family: u32,
1761    ) -> bool {
1762        ffi::GLFW_TRUE
1763            == unsafe {
1764                ffi::glfwGetPhysicalDevicePresentationSupport(
1765                    instance,
1766                    device,
1767                    queue_family as c_uint,
1768                )
1769            }
1770    }
1771
1772    /// Constructs a `Joystick` handle corresponding to the supplied `JoystickId`.
1773    pub fn get_joystick(&self, id: JoystickId) -> Joystick {
1774        Joystick {
1775            id,
1776            glfw: self.clone(),
1777        }
1778    }
1779
1780    /// Wrapper for `glfwRawMouseMotionSupported`.
1781    pub fn supports_raw_motion(&self) -> bool {
1782        unsafe { ffi::glfwRawMouseMotionSupported() == ffi::GLFW_TRUE }
1783    }
1784
1785    /// Parses the specified ASCII encoded string and updates the internal list with any gamepad
1786    /// mappings it finds. This string may contain either a single gamepad mapping or many mappings
1787    /// separated by newlines. The parser supports the full format of the `gamecontrollerdb.txt`
1788    /// source file including empty lines and comments.
1789    ///
1790    /// Wrapper for `glfwUpdateGamepadMappings`.
1791    ///
1792    /// # Returns
1793    ///
1794    /// `true` if successful, or `false` if an error occurred.
1795    pub fn update_gamepad_mappings(&self, mappings: &str) -> bool {
1796        unsafe {
1797            with_c_str(mappings, |mappings| {
1798                ffi::glfwUpdateGamepadMappings(mappings) == ffi::GLFW_TRUE
1799            })
1800        }
1801    }
1802}
1803
1804impl Clone for Glfw {
1805    fn clone(&self) -> Self {
1806        REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
1807        Glfw {
1808            phantom: std::marker::PhantomData,
1809        }
1810    }
1811}
1812
1813impl Drop for Glfw {
1814    fn drop(&mut self) {
1815        let old_diff = REF_COUNT_FOR_GLFW.fetch_sub(1, Ordering::SeqCst);
1816        if old_diff == 1 {
1817            unsafe {
1818                ffi::glfwTerminate();
1819            }
1820        }
1821    }
1822}
1823
1824fn glfw_channel<T>(initial_capacity: usize, max_len: usize) -> (GlfwSender<T>, GlfwReceiver<T>) {
1825    let shared = Arc::new(SharedTransmitter {
1826        queue: Mutex::new(VecDeque::with_capacity(initial_capacity)),
1827        max_len,
1828    });
1829    let (mpsc_sender, mpsc_receiver) = channel();
1830
1831    let sender = GlfwSender {
1832        transmitter: shared.clone(),
1833        sender: mpsc_sender,
1834    };
1835    let receiver = GlfwReceiver {
1836        transmitter: shared.clone(),
1837        receiver: mpsc_receiver,
1838    };
1839    (sender, receiver)
1840}
1841
1842#[derive(Debug)]
1843struct SharedTransmitter<T> {
1844    queue: Mutex<VecDeque<T>>,
1845    max_len: usize,
1846}
1847
1848#[derive(Debug, Clone)]
1849struct GlfwSender<T> {
1850    transmitter: Arc<SharedTransmitter<T>>,
1851    sender: Sender<T>,
1852}
1853
1854impl<T> GlfwSender<T> {
1855    fn send(&self, v: T) {
1856        let mut queue = self.transmitter.queue.lock().unwrap();
1857        if queue.len() >= self.transmitter.max_len {
1858            let _ = self.sender.send(v);
1859        } else {
1860            queue.push_back(v);
1861        }
1862    }
1863}
1864
1865#[derive(Debug)]
1866pub struct GlfwReceiver<T> {
1867    transmitter: Arc<SharedTransmitter<T>>,
1868    receiver: Receiver<T>,
1869}
1870
1871impl<T> GlfwReceiver<T> {
1872    pub fn receive(&self) -> Option<T> {
1873        let ret = self.transmitter.queue.lock().unwrap().pop_front();
1874        if ret.is_some() {
1875            ret
1876        } else {
1877            match self.receiver.try_recv() {
1878                Ok(ret) => Some(ret),
1879                Err(_) => None,
1880            }
1881        }
1882    }
1883}
1884
1885struct WindowCallbacks {
1886    window_ptr: *mut Window,
1887    sender: GlfwSender<(f64, WindowEvent)>,
1888    pos_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1889    size_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1890    close_callback: Option<Box<dyn FnMut(&mut Window)>>,
1891    refresh_callback: Option<Box<dyn FnMut(&mut Window)>>,
1892    focus_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1893    iconify_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1894    framebuffer_size_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1895    key_callback: Option<Box<dyn FnMut(&mut Window, Key, Scancode, Action, Modifiers)>>,
1896    char_callback: Option<Box<dyn FnMut(&mut Window, char)>>,
1897    char_mods_callback: Option<Box<dyn FnMut(&mut Window, char, Modifiers)>>,
1898    mouse_button_callback: Option<Box<dyn FnMut(&mut Window, MouseButton, Action, Modifiers)>>,
1899    cursor_pos_callback: Option<Box<dyn FnMut(&mut Window, f64, f64)>>,
1900    cursor_enter_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1901    scroll_callback: Option<Box<dyn FnMut(&mut Window, f64, f64)>>,
1902    drag_and_drop_callback: Option<Box<dyn FnMut(&mut Window, Vec<PathBuf>)>>,
1903    maximize_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1904    content_scale_callback: Option<Box<dyn FnMut(&mut Window, f32, f32)>>,
1905    pos_polling: bool,
1906    size_polling: bool,
1907    close_polling: bool,
1908    refresh_polling: bool,
1909    focus_polling: bool,
1910    iconify_polling: bool,
1911    framebuffer_size_polling: bool,
1912    key_polling: bool,
1913    char_polling: bool,
1914    char_mods_polling: bool,
1915    mouse_button_polling: bool,
1916    cursor_pos_polling: bool,
1917    cursor_enter_polling: bool,
1918    scroll_polling: bool,
1919    drag_and_drop_polling: bool,
1920    maximize_polling: bool,
1921    content_scale_polling: bool,
1922}
1923
1924impl WindowCallbacks {
1925    fn new(sender: GlfwSender<(f64, WindowEvent)>) -> Self {
1926        Self {
1927            window_ptr: std::ptr::null_mut(),
1928            sender,
1929            pos_callback: None,
1930            size_callback: None,
1931            close_callback: None,
1932            refresh_callback: None,
1933            focus_callback: None,
1934            iconify_callback: None,
1935            framebuffer_size_callback: None,
1936            key_callback: None,
1937            char_callback: None,
1938            char_mods_callback: None,
1939            mouse_button_callback: None,
1940            cursor_pos_callback: None,
1941            cursor_enter_callback: None,
1942            scroll_callback: None,
1943            drag_and_drop_callback: None,
1944            maximize_callback: None,
1945            content_scale_callback: None,
1946            pos_polling: false,
1947            size_polling: false,
1948            close_polling: false,
1949            refresh_polling: false,
1950            focus_polling: false,
1951            iconify_polling: false,
1952            framebuffer_size_polling: false,
1953            key_polling: false,
1954            char_polling: false,
1955            char_mods_polling: false,
1956            mouse_button_polling: false,
1957            cursor_pos_polling: false,
1958            cursor_enter_polling: false,
1959            scroll_polling: false,
1960            drag_and_drop_polling: false,
1961            maximize_polling: false,
1962            content_scale_polling: false,
1963        }
1964    }
1965
1966    fn get_callbacks<'a>(window: *mut GLFWwindow) -> &'a mut WindowCallbacks {
1967        unsafe { &mut *(ffi::glfwGetWindowUserPointer(window) as *mut WindowCallbacks) }
1968    }
1969}
1970
1971/// Wrapper for `glfwGetError`.
1972pub fn get_error() -> Error {
1973    unsafe { mem::transmute(ffi::glfwGetError(null_mut())) }
1974}
1975
1976/// Wrapper for `glfwGetError`.
1977pub fn get_error_string() -> (Error, String) {
1978    unsafe {
1979        let mut description: *const c_char = null();
1980        let error: Error = mem::transmute(ffi::glfwGetError(&mut description));
1981        (error, string_from_c_str(description))
1982    }
1983}
1984
1985/// Wrapper for `glfwGetVersion`.
1986pub fn get_version() -> Version {
1987    unsafe {
1988        let mut major = 0;
1989        let mut minor = 0;
1990        let mut patch = 0;
1991        ffi::glfwGetVersion(&mut major, &mut minor, &mut patch);
1992        Version {
1993            major: major as u64,
1994            minor: minor as u64,
1995            patch: patch as u64,
1996        }
1997    }
1998}
1999
2000/// Replacement for `String::from_raw_buf`
2001pub unsafe fn string_from_c_str(c_str: *const c_char) -> String {
2002    String::from_utf8_lossy(CStr::from_ptr(c_str).to_bytes()).into_owned()
2003}
2004
2005/// Like `string_from_c_str`, but handles null pointers correctly
2006pub unsafe fn string_from_nullable_c_str(c_str: *const c_char) -> Option<String> {
2007    if c_str.is_null() {
2008        None
2009    } else {
2010        Some(string_from_c_str(c_str))
2011    }
2012}
2013
2014/// Replacement for `ToCStr::with_c_str`
2015pub fn with_c_str<F, T>(s: &str, f: F) -> T
2016where
2017    F: FnOnce(*const c_char) -> T,
2018{
2019    let c_str = CString::new(s.as_bytes());
2020    f(c_str.unwrap().as_bytes_with_nul().as_ptr() as *const _)
2021}
2022
2023/// Wrapper for `glfwGetVersionString`.
2024pub fn get_version_string() -> String {
2025    unsafe { string_from_c_str(ffi::glfwGetVersionString()) }
2026}
2027
2028/// A struct that wraps a `*GLFWmonitor` handle.
2029#[allow(missing_copy_implementations)]
2030pub struct Monitor {
2031    ptr: *mut ffi::GLFWmonitor,
2032}
2033
2034impl std::fmt::Debug for Monitor {
2035    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2036        write!(f, "Monitor({:p})", self.ptr)
2037    }
2038}
2039
2040impl Monitor {
2041    /// Wrapper for `glfwGetMonitorPos`.
2042    pub fn get_pos(&self) -> (i32, i32) {
2043        unsafe {
2044            let mut xpos = 0;
2045            let mut ypos = 0;
2046            ffi::glfwGetMonitorPos(self.ptr, &mut xpos, &mut ypos);
2047            (xpos as i32, ypos as i32)
2048        }
2049    }
2050
2051    /// Wrapper for `glfwGetMonitorPhysicalSize`.
2052    pub fn get_physical_size(&self) -> (i32, i32) {
2053        unsafe {
2054            let mut width = 0;
2055            let mut height = 0;
2056            ffi::glfwGetMonitorPhysicalSize(self.ptr, &mut width, &mut height);
2057            (width as i32, height as i32)
2058        }
2059    }
2060
2061    /// Wrapper for `glfwGetMonitorName`.
2062    pub fn get_name(&self) -> Option<String> {
2063        unsafe { string_from_nullable_c_str(ffi::glfwGetMonitorName(self.ptr)) }
2064    }
2065
2066    /// Wrapper for `glfwGetVideoModes`.
2067    pub fn get_video_modes(&self) -> Vec<VidMode> {
2068        unsafe {
2069            let mut count = 0;
2070            let ptr = ffi::glfwGetVideoModes(self.ptr, &mut count);
2071            slice::from_raw_parts(ptr, count as usize)
2072                .iter()
2073                .map(VidMode::from_glfw_vid_mode)
2074                .collect()
2075        }
2076    }
2077
2078    /// Wrapper for `glfwGetVideoMode`.
2079    pub fn get_video_mode(&self) -> Option<VidMode> {
2080        unsafe {
2081            // TODO: Can be returned to as_ref + map as in previous commit when (if?) as_ref
2082            // stabilizes.
2083            let ptr = ffi::glfwGetVideoMode(self.ptr);
2084            if ptr.is_null() {
2085                None
2086            } else {
2087                Some(VidMode::from_glfw_vid_mode(&*ptr))
2088            }
2089        }
2090    }
2091
2092    /// Wrapper for `glfwSetGamma`.
2093    pub fn set_gamma(&mut self, gamma: f32) {
2094        unsafe {
2095            ffi::glfwSetGamma(self.ptr, gamma as c_float);
2096        }
2097    }
2098
2099    /// Wrapper for `glfwGetGammaRamp`.
2100    pub fn get_gamma_ramp(&self) -> GammaRamp {
2101        unsafe {
2102            let llramp = *ffi::glfwGetGammaRamp(self.ptr);
2103            GammaRamp {
2104                red: slice::from_raw_parts(llramp.red as *const c_ushort, llramp.size as usize)
2105                    .iter()
2106                    .copied()
2107                    .collect(),
2108                green: slice::from_raw_parts(llramp.green as *const c_ushort, llramp.size as usize)
2109                    .iter()
2110                    .copied()
2111                    .collect(),
2112                blue: slice::from_raw_parts(llramp.blue as *const c_ushort, llramp.size as usize)
2113                    .iter()
2114                    .copied()
2115                    .collect(),
2116            }
2117        }
2118    }
2119
2120    /// Wrapper for `glfwSetGammaRamp`.
2121    pub fn set_gamma_ramp(&mut self, ramp: &mut GammaRamp) {
2122        unsafe {
2123            ffi::glfwSetGammaRamp(
2124                self.ptr,
2125                &ffi::GLFWgammaramp {
2126                    red: ramp.red.as_mut_ptr(),
2127                    green: ramp.green.as_mut_ptr(),
2128                    blue: ramp.blue.as_mut_ptr(),
2129                    size: ramp.red.len() as u32,
2130                },
2131            );
2132        }
2133    }
2134
2135    /// Wrapper for `glfwGetMonitorContentScale`.
2136    pub fn get_content_scale(&self) -> (f32, f32) {
2137        unsafe {
2138            let mut xscale = 0.0_f32;
2139            let mut yscale = 0.0_f32;
2140            ffi::glfwGetMonitorContentScale(self.ptr, &mut xscale, &mut yscale);
2141            (xscale, yscale)
2142        }
2143    }
2144
2145    /// Wrapper for `glfwGetMonitorWorkarea`.
2146    pub fn get_workarea(&self) -> (i32, i32, i32, i32) {
2147        unsafe {
2148            let mut xpos = 0;
2149            let mut ypos = 0;
2150            let mut width = 0;
2151            let mut height = 0;
2152            ffi::glfwGetMonitorWorkarea(self.ptr, &mut xpos, &mut ypos, &mut width, &mut height);
2153            (xpos, ypos, width, height)
2154        }
2155    }
2156}
2157
2158/// Monitor events.
2159#[repr(i32)]
2160#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2161#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2162pub enum MonitorEvent {
2163    Connected = ffi::GLFW_CONNECTED,
2164    Disconnected = ffi::GLFW_DISCONNECTED,
2165}
2166
2167impl VidMode {
2168    fn from_glfw_vid_mode(mode: &ffi::GLFWvidmode) -> VidMode {
2169        VidMode {
2170            width: mode.width as u32,
2171            height: mode.height as u32,
2172            red_bits: mode.redBits as u32,
2173            green_bits: mode.greenBits as u32,
2174            blue_bits: mode.blueBits as u32,
2175            refresh_rate: mode.refreshRate as u32,
2176        }
2177    }
2178}
2179
2180impl fmt::Debug for VidMode {
2181    /// Returns a string representation of the video mode.
2182    ///
2183    /// # Returns
2184    ///
2185    /// A string in the form:
2186    ///
2187    /// ~~~ignore
2188    /// ~"[width] x [height], [total_bits] ([red_bits] [green_bits] [blue_bits]) [refresh_rate] Hz"
2189    /// ~~~
2190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2191        write!(
2192            f,
2193            "{} x {}, {} = {} + {} + {}, {} Hz",
2194            self.width,
2195            self.height,
2196            self.red_bits + self.green_bits + self.blue_bits,
2197            self.red_bits,
2198            self.green_bits,
2199            self.blue_bits,
2200            self.refresh_rate
2201        )
2202    }
2203}
2204
2205/// Window hints that can be set using the `window_hint` function.
2206#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2207#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2208pub enum WindowHint {
2209    MousePassthrough(bool),
2210    /// Specifies the desired bit depth of the red component of the default framebuffer.
2211    RedBits(Option<u32>),
2212    /// Specifies the desired bit depth of the green component of the default framebuffer.
2213    GreenBits(Option<u32>),
2214    /// Specifies the desired bit depth of the blue component of the default framebuffer.
2215    BlueBits(Option<u32>),
2216    /// Specifies the desired bit depth of the alpha component of the default framebuffer.
2217    AlphaBits(Option<u32>),
2218    /// Specifies the desired bit depth of the depth component of the default framebuffer.
2219    DepthBits(Option<u32>),
2220    /// Specifies the desired bit depth of the stencil component of the default framebuffer.
2221    StencilBits(Option<u32>),
2222    /// Specifies the desired bit depth of the red component of the accumulation framebuffer.
2223    AccumRedBits(Option<u32>),
2224    /// Specifies the desired bit depth of the green component of the accumulation framebuffer.
2225    AccumGreenBits(Option<u32>),
2226    /// Specifies the desired bit depth of the blue component of the accumulation framebuffer.
2227    AccumBlueBits(Option<u32>),
2228    /// Specifies the desired bit depth of the alpha component of the accumulation framebuffer.
2229    AccumAlphaBits(Option<u32>),
2230    /// Specifies the desired number of auxiliary buffers.
2231    AuxBuffers(Option<u32>),
2232    /// Specifies whether to use stereoscopic rendering.
2233    Stereo(bool),
2234    /// Specifies the desired number of samples to use for multisampling. Zero
2235    /// disables multisampling.
2236    Samples(Option<u32>),
2237    /// Specifies whether the framebuffer should be sRGB capable.
2238    SRgbCapable(bool),
2239    /// Specifies the desired refresh rate for full screen windows. If set to `None`,
2240    /// the highest available refresh rate will be used.
2241    ///
2242    /// This hint is ignored for windowed mode windows.
2243    RefreshRate(Option<u32>),
2244    /// Specifies which `ClientApi` to create the context for.
2245    ClientApi(ClientApiHint),
2246    /// Specifies the major client API version that the created context must be
2247    /// compatible with.
2248    ///
2249    /// Window creation will fail if the resulting OpenGL version is less than
2250    /// the one requested.
2251    ContextVersionMajor(u32),
2252    /// Specifies the minor client API version that the created context must be
2253    /// compatible with.
2254    ///
2255    /// Window creation will fail if the resulting OpenGL version is less than
2256    /// the one requested.
2257    ContextVersionMinor(u32),
2258    /// Specifies the client API version that the created context must be
2259    /// compatible with. This is the same as successive calls to `window_hint`
2260    /// function with the `ContextVersionMajor` and `ContextVersionMinor` hints.
2261    ///
2262    /// Window creation will fail if the resulting OpenGL version is less than
2263    /// the one requested.
2264    ///
2265    /// If `ContextVersion(1, 0)` is requested, _most_ drivers will provide the
2266    /// highest available context.
2267    ContextVersion(u32, u32),
2268    /// Specifies the `ContextRobustness` strategy to be used.
2269    ContextRobustness(ContextRobustnessHint),
2270    /// Specifies whether the OpenGL context should be forward-compatible, i.e.
2271    /// one where all functionality deprecated in the requested version of
2272    /// OpenGL is removed. This may only be used if the requested OpenGL version
2273    /// is 3.0 or above.
2274    ///
2275    /// If another client API is requested, this hint is ignored.
2276    OpenGlForwardCompat(bool),
2277    /// Specifies whether to create a debug OpenGL context, which may have
2278    /// additional error and performance issue reporting functionality.
2279    ///
2280    /// If another client API is requested, this hint is ignored.
2281    OpenGlDebugContext(bool),
2282    /// Specifies which OpenGL profile to create the context for. If requesting
2283    /// an OpenGL version below 3.2, `OpenGlAnyProfile` must be used.
2284    ///
2285    /// If another client API is requested, this hint is ignored.
2286    OpenGlProfile(OpenGlProfileHint),
2287    /// Specifies whether the window will be resizable by the user. Even if this
2288    /// is set to `false`, the window can still be resized using the
2289    /// `Window::set_size` function.
2290    ///
2291    /// This hint is ignored for fullscreen windows.
2292    Resizable(bool),
2293    /// Specifies whether the window will be visible on creation.
2294    ///
2295    /// This hint is ignored for fullscreen windows.
2296    Visible(bool),
2297    /// Specifies whether the window will have platform-specific decorations
2298    /// such as a border, a close widget, etc.
2299    ///
2300    /// This hint is ignored for full screen windows.
2301    Decorated(bool),
2302    /// Specifies whether the (full screen) window will automatically iconify
2303    /// and restore the previous video mode on input focus loss.
2304    ///
2305    /// This hint is ignored for windowed mode windows.
2306    AutoIconify(bool),
2307    /// Specifies whether the window will be floating above other regular
2308    /// windows, also called topmost or always-on-top.
2309    ///
2310    /// This hint is ignored for full screen windows.
2311    Floating(bool),
2312    /// Specifies whether the windowed mode window will be given input focus when created.
2313    ///
2314    /// This hint is ignored for full screen and initially hidden windows.
2315    Focused(bool),
2316    /// Specifies whether the windowed mode window will be maximized when created.
2317    ///
2318    /// This hint is ignored for full screen windows.
2319    Maximized(bool),
2320    /// Specifies whether the OpenGL or OpenGL ES contexts do not emit errors,
2321    /// allowing for better performance in some situations.
2322    ContextNoError(bool),
2323    /// Specifies which context creation API to use to create the context.
2324    ContextCreationApi(ContextCreationApi),
2325    /// Specifies the behavior of the OpenGL pipeline when a context is transferred between threads
2326    ContextReleaseBehavior(ContextReleaseBehavior),
2327    /// Specifies whether the framebuffer should be double buffered.
2328    ///
2329    /// You nearly always want to use double buffering.
2330    ///
2331    /// Note that setting this to false will make `swap_buffers` do nothing useful,
2332    /// and your scene will have to be displayed some other way.
2333    DoubleBuffer(bool),
2334    /// Speficies whether the cursor should be centered over newly created full screen windows.
2335    ///
2336    /// This hint is ignored for windowed mode windows.
2337    CenterCursor(bool),
2338    /// Specifies whether the window framebuffer will be transparent.
2339    ///
2340    /// If enabled and supported by the system, the window framebuffer alpha channel will be used
2341    /// to combine the framebuffer with the background. This does not affect window decorations.
2342    TransparentFramebuffer(bool),
2343    /// Specifies whether the window will be given input focus when `Window::show` is called.
2344    FocusOnShow(bool),
2345    /// Specifies whether the window content area should be resized based on the monitor current
2346    /// scale of any monitor it is placed on.
2347    ///
2348    /// This includes the initial placement when the window is created.
2349    ScaleToMonitor(bool),
2350    /// Specifies whether to use full resolution framebuffers on Retina displays.
2351    ///
2352    /// This is ignored on platforms besides macOS.
2353    CocoaRetinaFramebuffer(bool),
2354    /// Specifies the UTF-8 encoded name to use for autosaving the window frame, or if empty
2355    /// disables frame autosaving for the window.
2356    ///
2357    /// This is ignored on platforms besides macOS.
2358    CocoaFrameName(Option<String>),
2359    /// Specifies whether to in participate in Automatic Graphics Switching, i.e. to allow the
2360    /// system to choose the integrated GPU for the OpenGL context and move it between GPUs if
2361    /// necessary or whether to force it to always run on the discrete GPU.
2362    ///
2363    /// Simpler programs and tools may want to enable this to save power, while games and other
2364    /// applications performing advanced rendering will want to leave it disabled.
2365    //
2366    //  A bundled application that wishes to participate in Automatic Graphics Switching should also
2367    // declare this in its `Info.plist` by setting the `NSSupportsAutomaticGraphicsSwitching` key to
2368    // `true`.
2369    ///
2370    /// This only affects systems with both integrated and discrete GPUs. This is ignored on
2371    /// platforms besides macOS.
2372    CocoaGraphicsSwitching(bool),
2373    /// Specifies the desired ASCII-encoded class part of the ICCCM `WM_CLASS` window property.
2374    X11ClassName(Option<String>),
2375    /// Specifies the desired ASCII-encoded instance part of the ICCCM `WM_CLASS` window property.
2376    X11InstanceName(Option<String>),
2377}
2378
2379/// Client API tokens.
2380#[repr(i32)]
2381#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2382#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2383pub enum ClientApiHint {
2384    NoApi = ffi::GLFW_NO_API,
2385    OpenGl = ffi::GLFW_OPENGL_API,
2386    OpenGlEs = ffi::GLFW_OPENGL_ES_API,
2387}
2388
2389/// Context robustness tokens.
2390#[repr(i32)]
2391#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2392#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2393pub enum ContextRobustnessHint {
2394    NoRobustness = ffi::GLFW_NO_ROBUSTNESS,
2395    NoResetNotification = ffi::GLFW_NO_RESET_NOTIFICATION,
2396    LoseContextOnReset = ffi::GLFW_LOSE_CONTEXT_ON_RESET,
2397}
2398
2399/// OpenGL profile tokens.
2400#[repr(i32)]
2401#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2402#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2403pub enum OpenGlProfileHint {
2404    Any = ffi::GLFW_OPENGL_ANY_PROFILE,
2405    Core = ffi::GLFW_OPENGL_CORE_PROFILE,
2406    Compat = ffi::GLFW_OPENGL_COMPAT_PROFILE,
2407}
2408
2409/// Describes the mode of a window
2410#[derive(Copy, Clone, Debug)]
2411pub enum WindowMode<'a> {
2412    /// Full screen mode. Contains the monitor on which the window is displayed.
2413    FullScreen(&'a Monitor),
2414
2415    /// Windowed mode.
2416    Windowed,
2417}
2418
2419/// Private conversion methods for `glfw::WindowMode`
2420impl<'a> WindowMode<'a> {
2421    /// Returns a pointer to a monitor if the window is fullscreen, otherwise
2422    /// it returns a null pointer (if it is in windowed mode).
2423    fn to_ptr(&self) -> *mut ffi::GLFWmonitor {
2424        match *self {
2425            WindowMode::FullScreen(monitor) => monitor.ptr,
2426            WindowMode::Windowed => ptr::null_mut(),
2427        }
2428    }
2429}
2430
2431bitflags! {
2432    #[doc = "Key modifiers (e.g., Shift, Control, Alt, Super)"]
2433    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2434    pub struct Modifiers: ::std::os::raw::c_int {
2435        const Shift       = crate::ffi::GLFW_MOD_SHIFT;
2436        const Control     = crate::ffi::GLFW_MOD_CONTROL;
2437        const Alt         = crate::ffi::GLFW_MOD_ALT;
2438        const Super       = crate::ffi::GLFW_MOD_SUPER;
2439        const CapsLock    = crate::ffi::GLFW_MOD_CAPS_LOCK;
2440        const NumLock     = crate::ffi::GLFW_MOD_NUM_LOCK;
2441    }
2442}
2443
2444/// Keyboard code returned by the OS
2445pub type Scancode = c_int;
2446
2447/// Window event messages.
2448#[derive(Clone, PartialEq, PartialOrd, Debug)]
2449#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2450pub enum WindowEvent {
2451    Pos(i32, i32),
2452    Size(i32, i32),
2453    Close,
2454    Refresh,
2455    Focus(bool),
2456    Iconify(bool),
2457    FramebufferSize(i32, i32),
2458    MouseButton(MouseButton, Action, Modifiers),
2459    CursorPos(f64, f64),
2460    CursorEnter(bool),
2461    Scroll(f64, f64),
2462    Key(Key, Scancode, Action, Modifiers),
2463    Char(char),
2464    CharModifiers(char, Modifiers),
2465    FileDrop(Vec<PathBuf>),
2466    Maximize(bool),
2467    ContentScale(f32, f32),
2468}
2469
2470/// Returns an iterator that yields until no more messages are contained in the
2471/// `Receiver`'s queue. This is useful for event handling where the blocking
2472/// behaviour of `Receiver::iter` is undesirable.
2473///
2474/// # Example
2475///
2476/// ~~~ignore
2477/// for event in glfw::flush_messages(&events) {
2478///     // handle event
2479/// }
2480/// ~~~
2481pub fn flush_messages<Message: Send>(
2482    receiver: &GlfwReceiver<Message>,
2483) -> FlushedMessages<'_, Message> {
2484    FlushedMessages(receiver)
2485}
2486
2487/// An iterator that yields until no more messages are contained in the
2488/// `Receiver`'s queue.
2489#[derive(Debug)]
2490pub struct FlushedMessages<'a, Message: Send>(&'a GlfwReceiver<Message>);
2491
2492unsafe impl<'a, Message: 'a + Send> Send for FlushedMessages<'a, Message> {}
2493
2494impl<'a, Message: 'static + Send> Iterator for FlushedMessages<'a, Message> {
2495    type Item = Message;
2496
2497    fn next(&mut self) -> Option<Message> {
2498        let FlushedMessages(receiver) = *self;
2499        receiver.receive()
2500    }
2501}
2502
2503/// A struct that wraps a `*GLFWwindow` handle.
2504#[derive(Debug)]
2505pub struct Window {
2506    ptr: *mut ffi::GLFWwindow,
2507    pub is_shared: bool,
2508    /// A `Sender` that can be cloned out to child `RenderContext`s.
2509    drop_sender: Option<Sender<()>>,
2510    /// Once all  child`RenderContext`s have been dropped, calling `try_recv()`
2511    /// on the `drop_receiver` will result in an `Err(std::comm::Disconnected)`,
2512    /// indicating that it is safe to drop the `Window`.
2513    #[allow(unused)]
2514    drop_receiver: Receiver<()>,
2515    /// This is here to allow owning the current Cursor object instead
2516    /// of forcing the user to take care of its lifetime.
2517    current_cursor: Option<Cursor>,
2518    pub glfw: Glfw,
2519}
2520
2521impl Window {
2522    /// Returns the address of the specified client API or extension function if
2523    /// it is supported by the context associated with this Window. If this Window is not the
2524    /// current context, it will make it the current context.
2525    ///
2526    /// Wrapper for `glfwGetProcAddress`.
2527    pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
2528        if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
2529            self.make_current();
2530        }
2531
2532        self.glfw.get_proc_address_raw(procname)
2533    }
2534
2535    /// This function returns the address of the specified Vulkan core or extension function
2536    /// for the specified instance. If instance is set to NULL it can return any function
2537    /// exported from the Vulkan loader, including at least the following functions:
2538    ///
2539    /// * `vkEnumerateInstanceExtensionProperties`
2540    /// * `vkEnumerateInstanceLayerProperties`
2541    /// * `vkCreateInstance`
2542    /// * `vkGetInstanceProcAddr`
2543    ///
2544    /// If Vulkan is not available on the machine, this function returns `NULL`
2545    ///
2546    /// Wrapper for `glfwGetInstanceProcAddress`
2547    #[cfg(feature = "vulkan")]
2548    pub fn get_instance_proc_address(
2549        &mut self,
2550        instance: ffi::VkInstance,
2551        procname: &str,
2552    ) -> VkProc {
2553        self.glfw.get_instance_proc_address_raw(instance, procname)
2554    }
2555
2556    /// This function returns whether the specified queue family of the specified
2557    /// physical device supports presentation to the platform GLFW was built for.
2558    ///
2559    /// Wrapper for `glfwGetPhysicalDevicePresentationSupport`
2560    #[cfg(feature = "vulkan")]
2561    pub fn get_physical_device_presentation_support(
2562        &self,
2563        instance: ffi::VkInstance,
2564        device: ffi::VkPhysicalDevice,
2565        queue_family: u32,
2566    ) -> bool {
2567        self.glfw
2568            .get_physical_device_presentation_support_raw(instance, device, queue_family)
2569    }
2570
2571    /// wrapper for `glfwCreateWindowSurface`
2572    #[cfg(feature = "vulkan")]
2573    pub unsafe fn create_window_surface(
2574        &self,
2575        instance: ffi::VkInstance,
2576        allocator: *const ffi::VkAllocationCallbacks,
2577        surface: *mut ffi::VkSurfaceKHR,
2578    ) -> ffi::VkResult {
2579        unsafe { ffi::glfwCreateWindowSurface(instance, self.ptr, allocator, surface) }
2580    }
2581
2582    /// Creates a new shared window.
2583    ///
2584    /// Wrapper for `glfwCreateWindow`.
2585    pub fn create_shared(
2586        &self,
2587        width: u32,
2588        height: u32,
2589        title: &str,
2590        mode: WindowMode<'_>,
2591    ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
2592        self.glfw
2593            .create_window_intern(width, height, title, mode, Some(self))
2594    }
2595
2596    /// Calling this method forces the destructor to be called, closing the
2597    /// window.
2598    pub fn close(self) {}
2599
2600    /// Returns a render context that can be shared between tasks, allowing
2601    /// for concurrent rendering.
2602    pub fn render_context(&mut self) -> PRenderContext {
2603        PRenderContext(Box::new(RenderContext {
2604            ptr: self.ptr,
2605            glfw: self.glfw.clone(),
2606            // this will only be None after dropping so this is safe
2607            drop_sender: self.drop_sender.as_ref().unwrap().clone(),
2608        }))
2609    }
2610
2611    /// Wrapper for `glfwWindowShouldClose`.
2612    pub fn should_close(&self) -> bool {
2613        unsafe { ffi::glfwWindowShouldClose(self.ptr) == ffi::GLFW_TRUE }
2614    }
2615
2616    /// Wrapper for `glfwSetWindowShouldClose`.
2617    pub fn set_should_close(&mut self, value: bool) {
2618        unsafe { ffi::glfwSetWindowShouldClose(self.ptr, value as c_int) }
2619    }
2620
2621    /// Sets the title of the window.
2622    ///
2623    /// Wrapper for `glfwSetWindowTitle`.
2624    pub fn set_title(&mut self, title: &str) {
2625        unsafe {
2626            with_c_str(title, |title| {
2627                ffi::glfwSetWindowTitle(self.ptr, title);
2628            });
2629        }
2630    }
2631
2632    /// Wrapper for `glfwGetWindowPos`.
2633    pub fn get_pos(&self) -> (i32, i32) {
2634        unsafe {
2635            let mut xpos = 0;
2636            let mut ypos = 0;
2637            ffi::glfwGetWindowPos(self.ptr, &mut xpos, &mut ypos);
2638            (xpos as i32, ypos as i32)
2639        }
2640    }
2641
2642    /// Wrapper for `glfwSetWindowPos`.
2643    pub fn set_pos(&mut self, xpos: i32, ypos: i32) {
2644        unsafe {
2645            ffi::glfwSetWindowPos(self.ptr, xpos as c_int, ypos as c_int);
2646        }
2647    }
2648
2649    /// Wrapper for `glfwGetWindowSize`.
2650    pub fn get_size(&self) -> (i32, i32) {
2651        unsafe {
2652            let mut width = 0;
2653            let mut height = 0;
2654            ffi::glfwGetWindowSize(self.ptr, &mut width, &mut height);
2655            (width as i32, height as i32)
2656        }
2657    }
2658
2659    /// Wrapper for `glfwSetWindowSize`.
2660    pub fn set_size(&mut self, width: i32, height: i32) {
2661        unsafe {
2662            ffi::glfwSetWindowSize(self.ptr, width as c_int, height as c_int);
2663        }
2664    }
2665
2666    /// Wrapper for `glfwGetWindowFrameSize`
2667    ///
2668    /// Returns `(left, top, right, bottom)` edge window frame sizes, in screen coordinates.
2669    pub fn get_frame_size(&self) -> (i32, i32, i32, i32) {
2670        let (mut left, mut top, mut right, mut bottom): (i32, i32, i32, i32) = (0, 0, 0, 0);
2671
2672        unsafe {
2673            ffi::glfwGetWindowFrameSize(
2674                self.ptr,
2675                &mut left as *mut c_int,
2676                &mut top as *mut c_int,
2677                &mut right as *mut c_int,
2678                &mut bottom as *mut c_int,
2679            );
2680        }
2681
2682        (left, top, right, bottom)
2683    }
2684
2685    /// Wrapper for `glfwGetFramebufferSize`.
2686    pub fn get_framebuffer_size(&self) -> (i32, i32) {
2687        unsafe {
2688            let mut width = 0;
2689            let mut height = 0;
2690            ffi::glfwGetFramebufferSize(self.ptr, &mut width, &mut height);
2691            (width as i32, height as i32)
2692        }
2693    }
2694
2695    /// Wrapper for `glfwSetWindowAspectRatio`.
2696    pub fn set_aspect_ratio(&mut self, numer: u32, denum: u32) {
2697        unsafe { ffi::glfwSetWindowAspectRatio(self.ptr, numer as c_int, denum as c_int) }
2698    }
2699
2700    /// Wrapper for `glfwSetWindowSizeLimits`.
2701    ///
2702    /// A value of `None` is equivalent to `GLFW_DONT_CARE`.
2703    /// If `minwidth` or `minheight` are `None`, no minimum size is enforced.
2704    /// If `maxwidth` or `maxheight` are `None`, no maximum size is enforced.
2705    pub fn set_size_limits(
2706        &mut self,
2707        minwidth: Option<u32>,
2708        minheight: Option<u32>,
2709        maxwidth: Option<u32>,
2710        maxheight: Option<u32>,
2711    ) {
2712        unsafe {
2713            ffi::glfwSetWindowSizeLimits(
2714                self.ptr,
2715                unwrap_dont_care(minwidth),
2716                unwrap_dont_care(minheight),
2717                unwrap_dont_care(maxwidth),
2718                unwrap_dont_care(maxheight),
2719            )
2720        }
2721    }
2722
2723    /// Wrapper for `glfwIconifyWindow`.
2724    pub fn iconify(&mut self) {
2725        unsafe {
2726            ffi::glfwIconifyWindow(self.ptr);
2727        }
2728    }
2729
2730    /// Wrapper for `glfwRestoreWindow`.
2731    pub fn restore(&mut self) {
2732        unsafe {
2733            ffi::glfwRestoreWindow(self.ptr);
2734        }
2735    }
2736
2737    /// Wrapper for `glfwMaximizeWindow`
2738    pub fn maximize(&mut self) {
2739        unsafe { ffi::glfwMaximizeWindow(self.ptr) }
2740    }
2741
2742    /// Wrapper for `glfwShowWindow`.
2743    pub fn show(&mut self) {
2744        unsafe {
2745            ffi::glfwShowWindow(self.ptr);
2746        }
2747    }
2748
2749    /// Wrapper for `glfwHideWindow`.
2750    pub fn hide(&mut self) {
2751        unsafe {
2752            ffi::glfwHideWindow(self.ptr);
2753        }
2754    }
2755
2756    /// Returns whether the window is fullscreen or windowed.
2757    ///
2758    /// # Example
2759    ///
2760    /// ~~~ignore
2761    /// window.with_window_mode(|mode| {
2762    ///     match mode {
2763    ///         glfw::Windowed => println!("Windowed"),
2764    ///         glfw::FullScreen(m) => println!("FullScreen({})", m.get_name()),
2765    ///     }
2766    /// });
2767    /// ~~~
2768    pub fn with_window_mode<T, F>(&self, f: F) -> T
2769    where
2770        F: FnOnce(WindowMode<'_>) -> T,
2771    {
2772        let ptr = unsafe { ffi::glfwGetWindowMonitor(self.ptr) };
2773        if ptr.is_null() {
2774            f(WindowMode::Windowed)
2775        } else {
2776            f(WindowMode::FullScreen(&Monitor { ptr }))
2777        }
2778    }
2779
2780    /// Wrapper for `glfwSetWindowMonitor`
2781    pub fn set_monitor(
2782        &mut self,
2783        mode: WindowMode<'_>,
2784        xpos: i32,
2785        ypos: i32,
2786        width: u32,
2787        height: u32,
2788        refresh_rate: Option<u32>,
2789    ) {
2790        let monitor_ptr = if let WindowMode::FullScreen(monitor) = mode {
2791            monitor.ptr
2792        } else {
2793            ptr::null_mut()
2794        };
2795
2796        unsafe {
2797            ffi::glfwSetWindowMonitor(
2798                self.ptr,
2799                monitor_ptr,
2800                xpos as c_int,
2801                ypos as c_int,
2802                width as c_int,
2803                height as c_int,
2804                unwrap_dont_care(refresh_rate),
2805            )
2806        }
2807    }
2808
2809    /// Wrapper for `glfwFocusWindow`
2810    ///
2811    /// It is NOT recommended to use this function, as it steals focus from other applications
2812    /// and can be extremely disruptive to the user.
2813    pub fn focus(&mut self) {
2814        unsafe { ffi::glfwFocusWindow(self.ptr) }
2815    }
2816
2817    /// Wrapper for `glfwGetWindowAttrib` called with `FOCUSED`.
2818    pub fn is_focused(&self) -> bool {
2819        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_FOCUSED) == ffi::GLFW_TRUE }
2820    }
2821
2822    /// Wrapper for `glfwGetWindowAttrib` called with `ICONIFIED`.
2823    pub fn is_iconified(&self) -> bool {
2824        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_ICONIFIED) == ffi::GLFW_TRUE }
2825    }
2826
2827    /// Wrapper for `glfwGetWindowattrib` called with `MAXIMIZED`.
2828    pub fn is_maximized(&self) -> bool {
2829        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_MAXIMIZED) == ffi::GLFW_TRUE }
2830    }
2831
2832    /// Wrapper for `glfwGetWindowAttrib` called with `CLIENT_API`.
2833    pub fn get_client_api(&self) -> c_int {
2834        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CLIENT_API) }
2835    }
2836
2837    /// Wrapper for `glfwGetWindowAttrib` called with
2838    /// `CONTEXT_VERSION_MAJOR`, `CONTEXT_VERSION_MINOR` and `CONTEXT_REVISION`.
2839    ///
2840    /// # Returns
2841    ///
2842    /// The client API version of the window's context in a version struct.
2843    pub fn get_context_version(&self) -> Version {
2844        unsafe {
2845            Version {
2846                major: ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_VERSION_MAJOR) as u64,
2847                minor: ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_VERSION_MINOR) as u64,
2848                patch: ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_REVISION) as u64,
2849            }
2850        }
2851    }
2852
2853    /// Wrapper for `glfwGetWindowAttrib` called with `CONTEXT_ROBUSTNESS`.
2854    pub fn get_context_robustness(&self) -> c_int {
2855        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_ROBUSTNESS) }
2856    }
2857
2858    /// Wrapper for `glfwGetWindowAttrib` called with `OPENGL_FORWARD_COMPAT`.
2859    pub fn is_opengl_forward_compat(&self) -> bool {
2860        unsafe {
2861            ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_OPENGL_FORWARD_COMPAT) == ffi::GLFW_TRUE
2862        }
2863    }
2864
2865    /// Wrapper for `glfwGetWindowAttrib` called with `OPENGL_DEBUG_CONTEXT`.
2866    pub fn is_opengl_debug_context(&self) -> bool {
2867        unsafe {
2868            ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_OPENGL_DEBUG_CONTEXT) == ffi::GLFW_TRUE
2869        }
2870    }
2871
2872    /// Wrapper for `glfwGetWindowAttrib` called with `OPENGL_PROFILE`.
2873    pub fn get_opengl_profile(&self) -> c_int {
2874        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_OPENGL_PROFILE) }
2875    }
2876
2877    /// Wrapper for `glfwGetWindowAttrib` called with `RESIZABLE`.
2878    pub fn is_resizable(&self) -> bool {
2879        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_RESIZABLE) == ffi::GLFW_TRUE }
2880    }
2881
2882    /// Wrapper for `glfwSetWindowAttrib` called with `RESIZABLE`.
2883    pub fn set_resizable(&mut self, resizable: bool) {
2884        unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_RESIZABLE, resizable as c_int) }
2885    }
2886
2887    /// Wrapper for `glfwGetWindowAttrib` called with `VISIBLE`.
2888    pub fn is_visible(&self) -> bool {
2889        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_VISIBLE) == ffi::GLFW_TRUE }
2890    }
2891
2892    /// Wrapper for `glfwGetWindowAttrib` called with `DECORATED`.
2893    pub fn is_decorated(&self) -> bool {
2894        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_DECORATED) == ffi::GLFW_TRUE }
2895    }
2896
2897    /// Wrapper for `glfwSetWindowAttrib` called with `DECORATED`.
2898    pub fn set_decorated(&mut self, decorated: bool) {
2899        unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_DECORATED, decorated as c_int) }
2900    }
2901
2902    /// Wrapper for `glfwGetWindowAttrib` called with `AUTO_ICONIFY`.
2903    pub fn is_auto_iconify(&self) -> bool {
2904        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_AUTO_ICONIFY) == ffi::GLFW_TRUE }
2905    }
2906
2907    /// Wrapper for `glfwSetWindowAttrib` called with `AUTO_ICONIFY`.
2908    pub fn set_auto_iconify(&mut self, auto_iconify: bool) {
2909        unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_AUTO_ICONIFY, auto_iconify as c_int) }
2910    }
2911
2912    /// Wrapper for `glfwGetWindowAttrib` called with `FLOATING`.
2913    pub fn is_floating(&self) -> bool {
2914        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_FLOATING) == ffi::GLFW_TRUE }
2915    }
2916
2917    /// Wrapper for `glfwSetWindowAttrib` called with `FLOATING`.
2918    pub fn set_floating(&mut self, floating: bool) {
2919        unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_FLOATING, floating as c_int) }
2920    }
2921
2922    /// Wrapper for `glfwGetWindowAttrib` called with `TRANSPARENT_FRAMEBUFFER`.
2923    pub fn is_framebuffer_transparent(&self) -> bool {
2924        unsafe {
2925            ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_TRANSPARENT_FRAMEBUFFER) == ffi::GLFW_TRUE
2926        }
2927    }
2928
2929    /// Wrapper for `glfwGetWindowAttrib` called with `MOUSE_PASSTHROUGH`.
2930    pub fn is_mouse_passthrough(&self) -> bool {
2931        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_MOUSE_PASSTHROUGH) == ffi::GLFW_TRUE }
2932    }
2933
2934    /// Wrapper for `glfwSetWindowAttrib` called with `MOUSE_PASSTHROUGH`.
2935    pub fn set_mouse_passthrough(&mut self, passthrough: bool) {
2936        unsafe {
2937            ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_MOUSE_PASSTHROUGH, passthrough as c_int);
2938        }
2939    }
2940
2941    /// Wrapper for `glfwGetWindowAttrib` called with `FOCUS_ON_SHOW`.
2942    pub fn is_focus_on_show(&self) -> bool {
2943        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_FOCUS_ON_SHOW) == ffi::GLFW_TRUE }
2944    }
2945
2946    /// Wrapper for `glfwSetWindowAttrib` called with `FOCUS_ON_SHOW`.
2947    pub fn set_focus_on_show(&mut self, focus_on_show: bool) {
2948        unsafe {
2949            ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_FOCUS_ON_SHOW, focus_on_show as c_int)
2950        }
2951    }
2952
2953    /// Wrapper for `glfwGetWindowAttrib` called with `HOVERED`.
2954    pub fn is_hovered(&self) -> bool {
2955        unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_HOVERED) == ffi::GLFW_TRUE }
2956    }
2957
2958    new_callback!(
2959        doc -> "Wrapper for `glfwSetWindowPosCallback`.",
2960        set -> set_pos_callback,
2961        unset -> unset_pos_callback,
2962        poll -> set_pos_polling,
2963        callback_field -> pos_callback,
2964        poll_field -> pos_polling,
2965        window_event -> Pos(i32, i32),
2966        glfw -> glfwSetWindowPosCallback(x: c_int, y: c_int),
2967        convert_args -> (x as i32, y as i32),
2968        secret -> _pos_callback
2969    );
2970
2971    new_callback!(
2972        doc -> "Wrapper for `glfwSetWindowSizeCallback`.",
2973        set -> set_size_callback,
2974        unset -> unset_size_callback,
2975        poll -> set_size_polling,
2976        callback_field -> size_callback,
2977        poll_field -> size_polling,
2978        window_event -> Size(i32, i32),
2979        glfw -> glfwSetWindowSizeCallback(width: c_int, height: c_int),
2980        convert_args -> (width as i32, height as i32),
2981        secret -> _size_callback
2982    );
2983
2984    new_callback!(
2985        doc -> "Wrapper for `glfwSetWindowCloseCallback`.",
2986        set -> set_close_callback,
2987        unset -> unset_close_callback,
2988        poll -> set_close_polling,
2989        callback_field -> close_callback,
2990        poll_field -> close_polling,
2991        window_event -> Close,
2992        glfw -> glfwSetWindowCloseCallback(),
2993        convert_args -> (),
2994        secret -> _close_callback
2995    );
2996
2997    new_callback!(
2998        doc -> "Wrapper for `glfwSetWindowRefreshCallback`.",
2999        set -> set_refresh_callback,
3000        unset -> unset_refresh_callback,
3001        poll -> set_refresh_polling,
3002        callback_field -> refresh_callback,
3003        poll_field -> refresh_polling,
3004        window_event -> Refresh,
3005        glfw -> glfwSetWindowRefreshCallback(),
3006        convert_args -> (),
3007        secret -> _refresh_callback
3008    );
3009
3010    new_callback!(
3011        doc -> "Wrapper for `glfwSetWindowFocusCallback`.",
3012        set -> set_focus_callback,
3013        unset -> unset_focus_callback,
3014        poll -> set_focus_polling,
3015        callback_field -> focus_callback,
3016        poll_field -> focus_polling,
3017        window_event -> Focus(bool),
3018        glfw -> glfwSetWindowFocusCallback(focused: c_int),
3019        convert_args -> (focused == ffi::GLFW_TRUE),
3020        secret -> _focus_callback
3021    );
3022
3023    new_callback!(
3024        doc -> "Wrapper for `glfwSetWindowIconifyCallback`.",
3025        set -> set_iconify_callback,
3026        unset -> unset_iconify_callback,
3027        poll -> set_iconify_polling,
3028        callback_field -> iconify_callback,
3029        poll_field -> iconify_polling,
3030        window_event -> Iconify(bool),
3031        glfw -> glfwSetWindowIconifyCallback(iconified: c_int),
3032        convert_args -> (iconified == ffi::GLFW_TRUE),
3033        secret -> _iconify_callback
3034    );
3035
3036    new_callback!(
3037        doc -> "Wrapper for `glfwSetFramebufferSizeCallback`.",
3038        set -> set_framebuffer_size_callback,
3039        unset -> unset_framebuffer_size_callback,
3040        poll -> set_framebuffer_size_polling,
3041        callback_field -> framebuffer_size_callback,
3042        poll_field -> framebuffer_size_polling,
3043        window_event -> FramebufferSize(i32, i32),
3044        glfw -> glfwSetFramebufferSizeCallback(width: c_int, height: c_int),
3045        convert_args -> (width as i32, height as i32),
3046        secret -> _framebuffer_size_callback
3047    );
3048
3049    new_callback!(
3050        doc -> "Wrapper for `glfwSetKeyCallback`.",
3051        set -> set_key_callback,
3052        unset -> unset_key_callback,
3053        poll -> set_key_polling,
3054        callback_field -> key_callback,
3055        poll_field -> key_polling,
3056        window_event -> Key(Key, Scancode, Action, Modifiers),
3057        glfw -> glfwSetKeyCallback(key: c_int, scancode: c_int, action: c_int, mods: c_int),
3058        convert_args -> (
3059            mem::transmute(key),
3060            scancode, mem::transmute(action),
3061            Modifiers::from_bits(mods).unwrap()
3062        ),
3063        secret -> _key_callback
3064    );
3065
3066    new_callback!(
3067        doc -> "Wrapper for `glfwSetCharCallback`.",
3068        set -> set_char_callback,
3069        unset -> unset_char_callback,
3070        poll -> set_char_polling,
3071        callback_field -> char_callback,
3072        poll_field -> char_polling,
3073        window_event -> Char(char),
3074        glfw -> glfwSetCharCallback(character: c_uint),
3075        convert_args -> (::std::char::from_u32(character).unwrap()),
3076        secret -> _char_callback
3077    );
3078
3079    new_callback!(
3080        doc -> "Wrapper for `glfwSetCharModsCallback`.",
3081        set -> set_char_mods_callback,
3082        unset -> unset_char_mods_callback,
3083        poll -> set_char_mods_polling,
3084        callback_field -> char_mods_callback,
3085        poll_field -> char_mods_polling,
3086        window_event -> CharModifiers(char, Modifiers),
3087        glfw -> glfwSetCharModsCallback(character: c_uint, mods: c_int),
3088        convert_args -> (
3089            ::std::char::from_u32(character).unwrap(),
3090            Modifiers::from_bits(mods).unwrap()
3091        ),
3092        secret -> _char_mods_callback
3093    );
3094
3095    new_callback!(
3096        doc -> "Wrapper for `glfwSetMouseButtonCallback`.",
3097        set -> set_mouse_button_callback,
3098        unset -> unset_mouse_button_callback,
3099        poll -> set_mouse_button_polling,
3100        callback_field -> mouse_button_callback,
3101        poll_field -> mouse_button_polling,
3102        window_event -> MouseButton(MouseButton, Action, Modifiers),
3103        glfw -> glfwSetMouseButtonCallback(button: c_int, action: c_int, mods: c_int),
3104        convert_args -> (
3105            mem::transmute(button),
3106            mem::transmute(action),
3107            Modifiers::from_bits(mods).unwrap()
3108        ),
3109        secret -> _mouse_button_callback
3110    );
3111
3112    new_callback!(
3113        doc -> "Wrapper for `glfwSetCursorPosCallback`.",
3114        set -> set_cursor_pos_callback,
3115        unset -> unset_cursor_pos_callback,
3116        poll -> set_cursor_pos_polling,
3117        callback_field -> cursor_pos_callback,
3118        poll_field -> cursor_pos_polling,
3119        window_event -> CursorPos(f64, f64),
3120        glfw -> glfwSetCursorPosCallback(x: c_double, y: c_double),
3121        convert_args -> (x as f64, y as f64),
3122        secret -> _cursor_pos_callback
3123    );
3124
3125    new_callback!(
3126        doc -> "Wrapper for `glfwSetCursorEnterCallback`.",
3127        set -> set_cursor_enter_callback,
3128        unset -> unset_cursor_enter_callback,
3129        poll -> set_cursor_enter_polling,
3130        callback_field -> cursor_enter_callback,
3131        poll_field -> cursor_enter_polling,
3132        window_event -> CursorEnter(bool),
3133        glfw -> glfwSetCursorEnterCallback(entered: c_int),
3134        convert_args -> (entered == ffi::GLFW_TRUE),
3135        secret -> _cursor_enter_callback
3136    );
3137
3138    new_callback!(
3139        doc -> "Wrapper for `glfwSetScrollCallback`.",
3140        set -> set_scroll_callback,
3141        unset -> unset_scroll_callback,
3142        poll -> set_scroll_polling,
3143        callback_field -> scroll_callback,
3144        poll_field -> scroll_polling,
3145        window_event -> Scroll(f64, f64),
3146        glfw -> glfwSetScrollCallback(x: c_double, y: c_double),
3147        convert_args -> (x as f64, y as f64),
3148        secret -> _scroll_callback
3149    );
3150
3151    new_callback!(
3152        doc -> "Wrapper for `glfwSetDropCallback`.",
3153        set -> set_drag_and_drop_callback,
3154        unset -> unset_drag_and_drop_callback,
3155        poll -> set_drag_and_drop_polling,
3156        callback_field -> drag_and_drop_callback,
3157        poll_field -> drag_and_drop_polling,
3158        window_event -> FileDrop(Vec<PathBuf>),
3159        glfw -> glfwSetDropCallback(num_paths: c_int, paths: *mut *const c_char),
3160        convert_args -> ({
3161            slice::from_raw_parts(paths, num_paths as usize)
3162            .iter()
3163            .map(|path| PathBuf::from(std::str::from_utf8({
3164                CStr::from_ptr(*path)
3165                    .to_bytes()
3166            })
3167            .unwrap()
3168            .to_string()))
3169            .collect()
3170        }),
3171        secret -> _drag_and_drop_callback
3172    );
3173
3174    new_callback!(
3175        doc -> "Wrapper for `glfwSetWindowMaximizeCallback`.",
3176        set -> set_maximize_callback,
3177        unset -> unset_maximize_callback,
3178        poll -> set_maximize_polling,
3179        callback_field -> maximize_callback,
3180        poll_field -> maximize_polling,
3181        window_event -> Maximize(bool),
3182        glfw -> glfwSetWindowMaximizeCallback(maximized: c_int),
3183        convert_args -> (maximized == ffi::GLFW_TRUE),
3184        secret -> _maximize_callback
3185    );
3186
3187    new_callback!(
3188        doc -> "Wrapper for `glfwSetWindowContentScaleCallback`.",
3189        set -> set_content_scale_callback,
3190        unset -> unset_content_scale_callback,
3191        poll -> set_content_scale_polling,
3192        callback_field -> content_scale_callback,
3193        poll_field -> content_scale_polling,
3194        window_event -> ContentScale(f32, f32),
3195        glfw -> glfwSetWindowContentScaleCallback(xscale: c_float, yscale: c_float),
3196        convert_args -> (xscale as f32, yscale as f32),
3197        secret -> _content_scale_callback
3198    );
3199
3200    /// Starts or stops polling for all available events
3201    pub fn set_all_polling(&mut self, should_poll: bool) {
3202        self.set_pos_polling(should_poll);
3203        self.set_size_polling(should_poll);
3204        self.set_close_polling(should_poll);
3205        self.set_refresh_polling(should_poll);
3206        self.set_focus_polling(should_poll);
3207        self.set_iconify_polling(should_poll);
3208        self.set_framebuffer_size_polling(should_poll);
3209        self.set_key_polling(should_poll);
3210        self.set_char_polling(should_poll);
3211        self.set_char_mods_polling(should_poll);
3212        self.set_mouse_button_polling(should_poll);
3213        self.set_cursor_pos_polling(should_poll);
3214        self.set_cursor_enter_polling(should_poll);
3215        self.set_scroll_polling(should_poll);
3216        self.set_drag_and_drop_polling(should_poll);
3217        self.set_maximize_polling(should_poll);
3218        self.set_content_scale_polling(should_poll);
3219    }
3220
3221    /// Wrapper for `glfwGetInputMode` called with `CURSOR`.
3222    pub fn get_cursor_mode(&self) -> CursorMode {
3223        unsafe { mem::transmute(ffi::glfwGetInputMode(self.ptr, ffi::GLFW_CURSOR)) }
3224    }
3225
3226    /// Wrapper for `glfwSetInputMode` called with `CURSOR`.
3227    pub fn set_cursor_mode(&mut self, mode: CursorMode) {
3228        unsafe {
3229            ffi::glfwSetInputMode(self.ptr, ffi::GLFW_CURSOR, mode as c_int);
3230        }
3231    }
3232
3233    /// Wrapper for `glfwSetCursor` using `Cursor`
3234    ///
3235    /// The window will take ownership of the cursor, and will not Drop it
3236    /// until it is replaced or the window itself is destroyed.
3237    ///
3238    /// Returns the previously set Cursor or None if no cursor was set.
3239    pub fn set_cursor(&mut self, cursor: Option<Cursor>) -> Option<Cursor> {
3240        let previous = mem::replace(&mut self.current_cursor, cursor);
3241
3242        unsafe {
3243            ffi::glfwSetCursor(
3244                self.ptr,
3245                match self.current_cursor {
3246                    Some(ref cursor) => cursor.ptr,
3247                    None => ptr::null_mut(),
3248                },
3249            )
3250        }
3251
3252        previous
3253    }
3254
3255    /// Sets the window icon from the given images by called `glfwSetWindowIcon`
3256    ///
3257    /// Multiple images can be specified for allowing the OS to choose the best size where
3258    /// necessary.
3259    ///
3260    /// Example:
3261    ///
3262    /// ```ignore
3263    /// if let DynamicImage::ImageRgba8(icon) = image::open("examples/icon.png").unwrap() {
3264    ///    window.set_icon(vec![
3265    ///        imageops::resize(&icon, 16, 16, image::imageops::Lanczos3),
3266    ///        imageops::resize(&icon, 32, 32, image::imageops::Lanczos3),
3267    ///        imageops::resize(&icon, 48, 48, image::imageops::Lanczos3)
3268    ///    ]);
3269    /// }
3270    /// ```
3271    #[cfg(feature = "image")]
3272    pub fn set_icon(&mut self, images: Vec<image::RgbaImage>) {
3273        // When the images are turned into Vecs, the lifetimes of them go into the Vec lifetime
3274        // So they need to be kept until the function ends.
3275        let image_data: Vec<(Vec<_>, u32, u32)> = images
3276            .into_iter()
3277            .map(|image| {
3278                let (width, height) = image.dimensions();
3279
3280                (image.into_vec(), width, height)
3281            })
3282            .collect();
3283
3284        let glfw_images: Vec<ffi::GLFWimage> = image_data
3285            .iter()
3286            .map(|data| ffi::GLFWimage {
3287                width: data.1 as c_int,
3288                height: data.2 as c_int,
3289                pixels: data.0.as_ptr() as _,
3290            })
3291            .collect();
3292
3293        unsafe {
3294            ffi::glfwSetWindowIcon(
3295                self.ptr,
3296                glfw_images.len() as c_int,
3297                glfw_images.as_ptr() as *const ffi::GLFWimage,
3298            )
3299        }
3300    }
3301
3302    /// Sets the window icon via `glfwSetWindowIcon` from a set a set of vectors
3303    /// containing pixels in RGBA format (one pixel per 32-bit integer)
3304    pub fn set_icon_from_pixels(&mut self, images: Vec<PixelImage>) {
3305        let glfw_images: Vec<ffi::GLFWimage> = images
3306            .iter()
3307            .map(|image: &PixelImage| ffi::GLFWimage {
3308                width: image.width as c_int,
3309                height: image.height as c_int,
3310                pixels: image.pixels.as_ptr() as _,
3311            })
3312            .collect();
3313
3314        unsafe {
3315            ffi::glfwSetWindowIcon(
3316                self.ptr,
3317                glfw_images.len() as c_int,
3318                glfw_images.as_ptr() as *const ffi::GLFWimage,
3319            )
3320        }
3321    }
3322
3323    /// Wrapper for `glfwGetInputMode` called with `STICKY_KEYS`.
3324    pub fn has_sticky_keys(&self) -> bool {
3325        unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_STICKY_KEYS) == ffi::GLFW_TRUE }
3326    }
3327
3328    /// Wrapper for `glfwSetInputMode` called with `STICKY_KEYS`.
3329    pub fn set_sticky_keys(&mut self, value: bool) {
3330        unsafe {
3331            ffi::glfwSetInputMode(self.ptr, ffi::GLFW_STICKY_KEYS, value as c_int);
3332        }
3333    }
3334
3335    /// Wrapper for `glfwGetInputMode` called with `STICKY_MOUSE_BUTTONS`.
3336    pub fn has_sticky_mouse_buttons(&self) -> bool {
3337        unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_STICKY_MOUSE_BUTTONS) == ffi::GLFW_TRUE }
3338    }
3339
3340    /// Wrapper for `glfwSetInputMode` called with `STICKY_MOUSE_BUTTONS`.
3341    pub fn set_sticky_mouse_buttons(&mut self, value: bool) {
3342        unsafe {
3343            ffi::glfwSetInputMode(self.ptr, ffi::GLFW_STICKY_MOUSE_BUTTONS, value as c_int);
3344        }
3345    }
3346
3347    /// Wrapper for `glfwGetInputMode` called with `LOCK_KEY_MODS`
3348    pub fn does_store_lock_key_mods(&self) -> bool {
3349        unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_LOCK_KEY_MODS) == ffi::GLFW_TRUE }
3350    }
3351
3352    /// Wrapper for `glfwSetInputMode` called with `LOCK_KEY_MODS`
3353    pub fn set_store_lock_key_mods(&mut self, value: bool) {
3354        unsafe { ffi::glfwSetInputMode(self.ptr, ffi::GLFW_LOCK_KEY_MODS, value as c_int) }
3355    }
3356
3357    /// Wrapper for `glfwGetInputMode` called with `RAW_MOUSE_MOTION`
3358    pub fn uses_raw_mouse_motion(&self) -> bool {
3359        unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_RAW_MOUSE_MOTION) == ffi::GLFW_TRUE }
3360    }
3361
3362    /// Wrapper for `glfwSetInputMode` called with `RAW_MOUSE_MOTION`
3363    pub fn set_raw_mouse_motion(&mut self, value: bool) {
3364        unsafe { ffi::glfwSetInputMode(self.ptr, ffi::GLFW_RAW_MOUSE_MOTION, value as c_int) }
3365    }
3366
3367    /// Wrapper for `glfwGetKey`.
3368    pub fn get_key(&self, key: Key) -> Action {
3369        unsafe { mem::transmute(ffi::glfwGetKey(self.ptr, key as c_int)) }
3370    }
3371
3372    /// Wrapper for `glfwGetMouseButton`.
3373    pub fn get_mouse_button(&self, button: MouseButton) -> Action {
3374        unsafe { mem::transmute(ffi::glfwGetMouseButton(self.ptr, button as c_int)) }
3375    }
3376
3377    /// Wrapper for `glfwGetCursorPos`.
3378    pub fn get_cursor_pos(&self) -> (f64, f64) {
3379        unsafe {
3380            let mut xpos = 0.0;
3381            let mut ypos = 0.0;
3382            ffi::glfwGetCursorPos(self.ptr, &mut xpos, &mut ypos);
3383            (xpos as f64, ypos as f64)
3384        }
3385    }
3386
3387    /// Wrapper for `glfwSetCursorPos`.
3388    pub fn set_cursor_pos(&mut self, xpos: f64, ypos: f64) {
3389        unsafe {
3390            ffi::glfwSetCursorPos(self.ptr, xpos as c_double, ypos as c_double);
3391        }
3392    }
3393
3394    /// Wrapper for `glfwGetClipboardString`.
3395    pub fn set_clipboard_string(&mut self, string: &str) {
3396        unsafe {
3397            with_c_str(string, |string| {
3398                ffi::glfwSetClipboardString(self.ptr, string);
3399            });
3400        }
3401    }
3402
3403    /// Wrapper for `glfwGetClipboardString`.
3404    pub fn get_clipboard_string(&self) -> Option<String> {
3405        unsafe { string_from_nullable_c_str(ffi::glfwGetClipboardString(self.ptr)) }
3406    }
3407
3408    /// Wrapper for `glfwGetWindowOpacity`.
3409    pub fn get_opacity(&self) -> f32 {
3410        unsafe { ffi::glfwGetWindowOpacity(self.ptr) }
3411    }
3412
3413    /// Wrapper for `glfwSetWindowOpacity`.
3414    pub fn set_opacity(&mut self, opacity: f32) {
3415        unsafe { ffi::glfwSetWindowOpacity(self.ptr, opacity) }
3416    }
3417
3418    /// Wrapper for `glfwRequestWindowAttention`.
3419    pub fn request_attention(&mut self) {
3420        unsafe { ffi::glfwRequestWindowAttention(self.ptr) }
3421    }
3422
3423    /// Wrapper for `glfwGetWindowContentScale`.
3424    pub fn get_content_scale(&self) -> (f32, f32) {
3425        unsafe {
3426            let mut xscale = 0.0_f32;
3427            let mut yscale = 0.0_f32;
3428            ffi::glfwGetWindowContentScale(self.ptr, &mut xscale, &mut yscale);
3429            (xscale, yscale)
3430        }
3431    }
3432
3433    /// Wrapper for `glfwGetWin32Window`
3434    #[cfg(target_os = "windows")]
3435    pub fn get_win32_window(&self) -> *mut c_void {
3436        unsafe { ffi::glfwGetWin32Window(self.ptr) }
3437    }
3438
3439    /// Wrapper for `glfwGetWGLContext`
3440    #[cfg(target_os = "windows")]
3441    pub fn get_wgl_context(&self) -> *mut c_void {
3442        unsafe { ffi::glfwGetWGLContext(self.ptr) }
3443    }
3444
3445    /// Wrapper for `glfwGetCocoaWindow`
3446    #[cfg(target_os = "macos")]
3447    pub fn get_cocoa_window(&self) -> *mut c_void {
3448        unsafe { ffi::glfwGetCocoaWindow(self.ptr) }
3449    }
3450
3451    /// Wrapper for `glfwGetNSGLContext`
3452    #[cfg(target_os = "macos")]
3453    pub fn get_nsgl_context(&self) -> *mut c_void {
3454        unsafe { ffi::glfwGetNSGLContext(self.ptr) }
3455    }
3456
3457    /// Wrapper for `glfwGetX11Window`
3458    #[cfg(all(not(target_os = "windows"), not(target_os = "macos"), feature = "x11"))]
3459    pub fn get_x11_window(&self) -> usize {
3460        unsafe { ffi::glfwGetX11Window(self.ptr) }
3461    }
3462
3463    /// Wrapper for `glfwGetWaylandWindow`
3464    #[cfg(all(
3465        not(target_os = "windows"),
3466        not(target_os = "macos"),
3467        feature = "wayland"
3468    ))]
3469    pub fn get_wayland_window(&self) -> *mut c_void {
3470        unsafe { ffi::glfwGetWaylandWindow(self.ptr) }
3471    }
3472
3473    /// Wrapper for `glfwGetGLXContext`
3474    #[cfg(all(not(target_os = "windows"), not(target_os = "macos"), feature = "x11"))]
3475    pub fn get_glx_context(&self) -> usize {
3476        unsafe { ffi::glfwGetGLXContext(self.ptr) }
3477    }
3478}
3479
3480impl Drop for Window {
3481    /// Closes the window and performs the necessary cleanups. This will block
3482    /// until all associated `RenderContext`s were also dropped, and emit a
3483    /// `debug!` message to that effect.
3484    ///
3485    /// Wrapper for `glfwDestroyWindow`.
3486    fn drop(&mut self) {
3487        drop(self.drop_sender.take());
3488
3489        // Check if all senders from the child `RenderContext`s have hung up.
3490        #[cfg(feature = "log")]
3491        if self.drop_receiver.try_recv() != Err(std::sync::mpsc::TryRecvError::Disconnected) {
3492            debug!("Attempted to drop a Window before the `RenderContext` was dropped.");
3493            debug!("Blocking until the `RenderContext` was dropped.");
3494            let _ = self.drop_receiver.recv();
3495        }
3496
3497        if !self.ptr.is_null() {
3498            unsafe {
3499                let _: Box<WindowCallbacks> =
3500                    mem::transmute(ffi::glfwGetWindowUserPointer(self.ptr));
3501            }
3502        }
3503
3504        if !self.is_shared {
3505            unsafe {
3506                ffi::glfwDestroyWindow(self.ptr);
3507            }
3508        }
3509    }
3510}
3511
3512#[derive(Debug)]
3513#[repr(transparent)]
3514pub struct PRenderContext(Box<RenderContext>);
3515
3516impl Deref for PRenderContext {
3517    type Target = RenderContext;
3518    fn deref(&self) -> &Self::Target {
3519        self.0.deref()
3520    }
3521}
3522
3523impl DerefMut for PRenderContext {
3524    fn deref_mut(&mut self) -> &mut Self::Target {
3525        self.0.deref_mut()
3526    }
3527}
3528
3529unsafe impl Send for PRenderContext {}
3530unsafe impl Sync for PRenderContext {}
3531
3532#[cfg(feature = "raw-window-handle-v0-6")]
3533impl HasWindowHandle for PRenderContext {
3534    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3535        self.0.window_handle()
3536    }
3537}
3538
3539#[cfg(feature = "raw-window-handle-v0-6")]
3540impl HasDisplayHandle for PRenderContext {
3541    fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
3542        self.0.display_handle()
3543    }
3544}
3545
3546/// A rendering context that can be shared between tasks.
3547#[derive(Debug)]
3548pub struct RenderContext {
3549    ptr: *mut ffi::GLFWwindow,
3550    glfw: Glfw,
3551    /// As long as this sender is alive, it is not safe to drop the parent
3552    /// `Window`.
3553    #[allow(dead_code)]
3554    drop_sender: Sender<()>,
3555}
3556
3557impl RenderContext {
3558    /// Wrapper function, please refer to [`Window::get_proc_address`]
3559    pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
3560        if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
3561            self.make_current();
3562        }
3563
3564        self.glfw.get_proc_address_raw(procname)
3565    }
3566
3567    /// Wrapper function, please refer to [`Window::get_instance_proc_address`]
3568    #[cfg(feature = "vulkan")]
3569    pub fn get_instance_proc_address(
3570        &mut self,
3571        instance: ffi::VkInstance,
3572        procname: &str,
3573    ) -> VkProc {
3574        self.glfw.get_instance_proc_address_raw(instance, procname)
3575    }
3576
3577    /// Wrapper function, please refer to [`Window::get_physical_device_presentation_support`]
3578    #[cfg(feature = "vulkan")]
3579    pub fn get_physical_device_presentation_support(
3580        &self,
3581        instance: ffi::VkInstance,
3582        device: ffi::VkPhysicalDevice,
3583        queue_family: u32,
3584    ) -> bool {
3585        self.glfw
3586            .get_physical_device_presentation_support_raw(instance, device, queue_family)
3587    }
3588
3589    /// Wrapper function, please refer to [`Window::create_window_surface`]
3590    #[cfg(feature = "vulkan")]
3591    pub unsafe fn create_window_surface(
3592        &self,
3593        instance: ffi::VkInstance,
3594        allocator: *const ffi::VkAllocationCallbacks,
3595        surface: *mut ffi::VkSurfaceKHR,
3596    ) -> ffi::VkResult {
3597        unsafe { ffi::glfwCreateWindowSurface(instance, self.ptr, allocator, surface) }
3598    }
3599}
3600
3601unsafe impl Send for RenderContext {}
3602
3603/// Methods common to renderable contexts
3604pub trait Context {
3605    /// Returns the pointer to the underlying `GLFWwindow`.
3606    fn window_ptr(&self) -> *mut ffi::GLFWwindow;
3607
3608    /// Returns the unique identifier for this window.
3609    fn window_id(&self) -> WindowId {
3610        self.window_ptr() as WindowId
3611    }
3612
3613    /// Swaps the front and back buffers of the window. If the swap interval is
3614    /// greater than zero, the GPU driver waits the specified number of screen
3615    /// updates before swapping the buffers.
3616    ///
3617    /// Wrapper for `glfwSwapBuffers`.
3618    fn swap_buffers(&mut self) {
3619        let ptr = self.window_ptr();
3620        unsafe {
3621            ffi::glfwSwapBuffers(ptr);
3622        }
3623    }
3624
3625    /// Returns `true` if the window is the current context.
3626    fn is_current(&self) -> bool {
3627        self.window_ptr() == unsafe { ffi::glfwGetCurrentContext() }
3628    }
3629
3630    /// Wrapper for `glfwMakeContextCurrent`
3631    fn make_current(&mut self) {
3632        let ptr = self.window_ptr();
3633        unsafe {
3634            ffi::glfwMakeContextCurrent(ptr);
3635        }
3636    }
3637
3638    /// Wrapper for `glfwWindowShouldClose`.
3639    fn should_close(&self) -> bool {
3640        let ptr = self.window_ptr();
3641        unsafe { ffi::glfwWindowShouldClose(ptr) == ffi::GLFW_TRUE }
3642    }
3643
3644    /// Wrapper for `glfwSetWindowShouldClose`.
3645    fn set_should_close(&mut self, value: bool) {
3646        let ptr = self.window_ptr();
3647        unsafe {
3648            ffi::glfwSetWindowShouldClose(ptr, value as c_int);
3649        }
3650    }
3651
3652    /// Wrapper for `glfwPostEmptyEvent`.
3653    fn post_empty_event(&self) {
3654        unsafe { ffi::glfwPostEmptyEvent() }
3655    }
3656}
3657
3658impl Context for Window {
3659    fn window_ptr(&self) -> *mut ffi::GLFWwindow {
3660        self.ptr
3661    }
3662}
3663
3664impl Context for RenderContext {
3665    fn window_ptr(&self) -> *mut ffi::GLFWwindow {
3666        self.ptr
3667    }
3668}
3669
3670#[cfg(feature = "raw-window-handle-v0-6")]
3671impl HasWindowHandle for Window {
3672    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3673        Ok(unsafe { WindowHandle::borrow_raw(raw_window_handle(self)) })
3674    }
3675}
3676
3677#[cfg(feature = "raw-window-handle-v0-6")]
3678impl HasWindowHandle for RenderContext {
3679    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3680        Ok(unsafe { WindowHandle::borrow_raw(raw_window_handle(self)) })
3681    }
3682}
3683
3684#[cfg(feature = "raw-window-handle-v0-6")]
3685impl HasDisplayHandle for Window {
3686    fn display_handle(&'_ self) -> Result<DisplayHandle<'_>, HandleError> {
3687        Ok(unsafe { DisplayHandle::borrow_raw(raw_display_handle()) })
3688    }
3689}
3690
3691#[cfg(feature = "raw-window-handle-v0-6")]
3692impl HasDisplayHandle for RenderContext {
3693    fn display_handle(&'_ self) -> Result<DisplayHandle<'_>, HandleError> {
3694        Ok(unsafe { DisplayHandle::borrow_raw(raw_display_handle()) })
3695    }
3696}
3697
3698#[cfg(feature = "raw-window-handle-v0-5")]
3699unsafe impl HasRawWindowHandle for Window {
3700    fn raw_window_handle(&self) -> RawWindowHandle {
3701        raw_window_handle(self)
3702    }
3703}
3704
3705#[cfg(feature = "raw-window-handle-v0-5")]
3706unsafe impl HasRawWindowHandle for RenderContext {
3707    fn raw_window_handle(&self) -> RawWindowHandle {
3708        raw_window_handle(self)
3709    }
3710}
3711
3712#[cfg(feature = "raw-window-handle-v0-5")]
3713unsafe impl HasRawDisplayHandle for Window {
3714    fn raw_display_handle(&self) -> RawDisplayHandle {
3715        raw_display_handle()
3716    }
3717}
3718
3719#[cfg(feature = "raw-window-handle-v0-5")]
3720unsafe impl HasRawDisplayHandle for RenderContext {
3721    fn raw_display_handle(&self) -> RawDisplayHandle {
3722        raw_display_handle()
3723    }
3724}
3725
3726#[cfg(feature = "raw-window-handle-v0-6")]
3727fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
3728    #[cfg(target_family = "windows")]
3729    {
3730        use std::num::NonZeroIsize;
3731
3732        use raw_window_handle::Win32WindowHandle;
3733        let (hwnd, hinstance): (*mut std::ffi::c_void, *mut std::ffi::c_void) = unsafe {
3734            let hwnd = ffi::glfwGetWin32Window(context.window_ptr());
3735            let hinstance: *mut c_void =
3736                winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null()) as _;
3737            (hwnd, hinstance as _)
3738        };
3739        let mut handle = Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
3740        handle.hinstance = NonZeroIsize::new(hinstance as isize);
3741        RawWindowHandle::Win32(handle)
3742    }
3743    #[cfg(all(
3744        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3745        not(feature = "wayland")
3746    ))]
3747    {
3748        use raw_window_handle::XlibWindowHandle;
3749        let window =
3750            unsafe { ffi::glfwGetX11Window(context.window_ptr()) as std::os::raw::c_ulong };
3751        RawWindowHandle::Xlib(XlibWindowHandle::new(window))
3752    }
3753    #[cfg(all(
3754        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3755        feature = "wayland"
3756    ))]
3757    {
3758        use std::ptr::NonNull;
3759
3760        use raw_window_handle::WaylandWindowHandle;
3761        let surface = unsafe { ffi::glfwGetWaylandWindow(context.window_ptr()) };
3762        let handle = WaylandWindowHandle::new(
3763            NonNull::new(surface).expect("wayland window surface is null"),
3764        );
3765        RawWindowHandle::Wayland(handle)
3766    }
3767    #[cfg(target_os = "macos")]
3768    {
3769        use std::ptr::NonNull;
3770
3771        use objc2::msg_send_id;
3772        use objc2::rc::Id;
3773        use objc2::runtime::NSObject;
3774        use raw_window_handle::AppKitWindowHandle;
3775        let ns_window: *mut NSObject =
3776            unsafe { ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _ };
3777        let ns_view: Option<Id<NSObject>> = unsafe { msg_send_id![ns_window, contentView] };
3778        let ns_view = ns_view.expect("failed to access contentView on GLFW NSWindow");
3779        let ns_view: NonNull<NSObject> = NonNull::from(&*ns_view);
3780        let handle = AppKitWindowHandle::new(ns_view.cast());
3781        RawWindowHandle::AppKit(handle)
3782    }
3783    #[cfg(target_os = "emscripten")]
3784    {
3785        let _ = context; // to avoid unused lint
3786        let mut wh = raw_window_handle::WebWindowHandle::new(1);
3787        // glfw on emscripten only supports a single window. so, just hardcode it
3788        // sdl2 crate does the same. users can just add `data-raw-handle="1"` attribute to their
3789        // canvas element
3790        RawWindowHandle::Web(wh)
3791    }
3792}
3793
3794#[cfg(feature = "raw-window-handle-v0-6")]
3795fn raw_display_handle() -> RawDisplayHandle {
3796    #[cfg(target_family = "windows")]
3797    {
3798        use raw_window_handle::WindowsDisplayHandle;
3799        RawDisplayHandle::Windows(WindowsDisplayHandle::new())
3800    }
3801    #[cfg(all(
3802        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3803        not(feature = "wayland")
3804    ))]
3805    {
3806        use std::ptr::NonNull;
3807
3808        use raw_window_handle::XlibDisplayHandle;
3809        let display = NonNull::new(unsafe { ffi::glfwGetX11Display() });
3810        let handle = XlibDisplayHandle::new(display, 0);
3811        RawDisplayHandle::Xlib(handle)
3812    }
3813    #[cfg(all(
3814        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3815        feature = "wayland"
3816    ))]
3817    {
3818        use std::ptr::NonNull;
3819
3820        use raw_window_handle::WaylandDisplayHandle;
3821        let display = NonNull::new(unsafe { ffi::glfwGetWaylandDisplay().cast_mut() })
3822            .expect("wayland display is null");
3823        let handle = WaylandDisplayHandle::new(display);
3824        RawDisplayHandle::Wayland(handle)
3825    }
3826    #[cfg(target_os = "macos")]
3827    {
3828        use raw_window_handle::AppKitDisplayHandle;
3829        RawDisplayHandle::AppKit(AppKitDisplayHandle::new())
3830    }
3831    #[cfg(target_os = "emscripten")]
3832    {
3833        RawDisplayHandle::Web(raw_window_handle::WebDisplayHandle::new())
3834    }
3835}
3836
3837#[cfg(feature = "raw-window-handle-v0-5")]
3838fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
3839    #[cfg(target_family = "windows")]
3840    {
3841        use raw_window_handle::Win32WindowHandle;
3842        let (hwnd, hinstance) = unsafe {
3843            let hwnd = ffi::glfwGetWin32Window(context.window_ptr());
3844            let hinstance = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null());
3845            (hwnd, hinstance as _)
3846        };
3847        let mut handle = Win32WindowHandle::empty();
3848        handle.hwnd = hwnd;
3849        handle.hinstance = hinstance;
3850        RawWindowHandle::Win32(handle)
3851    }
3852    #[cfg(all(
3853        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3854        not(feature = "wayland")
3855    ))]
3856    {
3857        use raw_window_handle::XlibWindowHandle;
3858        let mut handle = XlibWindowHandle::empty();
3859        handle.window =
3860            unsafe { ffi::glfwGetX11Window(context.window_ptr()) as std::os::raw::c_ulong };
3861        RawWindowHandle::Xlib(handle)
3862    }
3863    #[cfg(all(
3864        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3865        feature = "wayland"
3866    ))]
3867    {
3868        use raw_window_handle::WaylandWindowHandle;
3869        let mut handle = WaylandWindowHandle::empty();
3870        handle.surface = unsafe { ffi::glfwGetWaylandWindow(context.window_ptr()) };
3871        RawWindowHandle::Wayland(handle)
3872    }
3873    #[cfg(target_os = "macos")]
3874    {
3875        use raw_window_handle::AppKitWindowHandle;
3876        let (ns_window, ns_view) = unsafe {
3877            let ns_window: *mut objc::runtime::Object =
3878                ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _;
3879            let ns_view: *mut objc::runtime::Object = objc::msg_send![ns_window, contentView];
3880            assert_ne!(ns_view, std::ptr::null_mut());
3881            (
3882                ns_window as *mut std::ffi::c_void,
3883                ns_view as *mut std::ffi::c_void,
3884            )
3885        };
3886        let mut handle = AppKitWindowHandle::empty();
3887        handle.ns_window = ns_window;
3888        handle.ns_view = ns_view;
3889        RawWindowHandle::AppKit(handle)
3890    }
3891    #[cfg(target_os = "emscripten")]
3892    {
3893        let _ = context; // to avoid unused lint
3894        let mut wh = raw_window_handle::WebWindowHandle::empty();
3895        // glfw on emscripten only supports a single window. so, just hardcode it
3896        // sdl2 crate does the same. users can just add `data-raw-handle="1"` attribute to their
3897        // canvas element
3898        wh.id = 1;
3899        RawWindowHandle::Web(wh)
3900    }
3901}
3902
3903#[cfg(feature = "raw-window-handle-v0-5")]
3904fn raw_display_handle() -> RawDisplayHandle {
3905    #[cfg(target_family = "windows")]
3906    {
3907        use raw_window_handle::WindowsDisplayHandle;
3908        RawDisplayHandle::Windows(WindowsDisplayHandle::empty())
3909    }
3910    #[cfg(all(
3911        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3912        not(feature = "wayland")
3913    ))]
3914    {
3915        use raw_window_handle::XlibDisplayHandle;
3916        let mut handle = XlibDisplayHandle::empty();
3917        handle.display = unsafe { ffi::glfwGetX11Display() };
3918        RawDisplayHandle::Xlib(handle)
3919    }
3920    #[cfg(all(
3921        any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3922        feature = "wayland"
3923    ))]
3924    {
3925        use raw_window_handle::WaylandDisplayHandle;
3926        let mut handle = WaylandDisplayHandle::empty();
3927        handle.display = unsafe { ffi::glfwGetWaylandDisplay() };
3928        RawDisplayHandle::Wayland(handle)
3929    }
3930    #[cfg(target_os = "macos")]
3931    {
3932        use raw_window_handle::AppKitDisplayHandle;
3933        RawDisplayHandle::AppKit(AppKitDisplayHandle::empty())
3934    }
3935    #[cfg(target_os = "emscripten")]
3936    {
3937        RawDisplayHandle::Web(raw_window_handle::WebDisplayHandle::empty())
3938    }
3939}
3940
3941/// Wrapper for `glfwMakeContextCurrent`.
3942pub fn make_context_current(context: Option<&dyn Context>) {
3943    match context {
3944        Some(ctx) => unsafe { ffi::glfwMakeContextCurrent(ctx.window_ptr()) },
3945        None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
3946    }
3947}
3948
3949/// Joystick identifier tokens.
3950#[repr(i32)]
3951#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
3952#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3953pub enum JoystickId {
3954    Joystick1 = ffi::GLFW_JOYSTICK_1,
3955    Joystick2 = ffi::GLFW_JOYSTICK_2,
3956    Joystick3 = ffi::GLFW_JOYSTICK_3,
3957    Joystick4 = ffi::GLFW_JOYSTICK_4,
3958    Joystick5 = ffi::GLFW_JOYSTICK_5,
3959    Joystick6 = ffi::GLFW_JOYSTICK_6,
3960    Joystick7 = ffi::GLFW_JOYSTICK_7,
3961    Joystick8 = ffi::GLFW_JOYSTICK_8,
3962    Joystick9 = ffi::GLFW_JOYSTICK_9,
3963    Joystick10 = ffi::GLFW_JOYSTICK_10,
3964    Joystick11 = ffi::GLFW_JOYSTICK_11,
3965    Joystick12 = ffi::GLFW_JOYSTICK_12,
3966    Joystick13 = ffi::GLFW_JOYSTICK_13,
3967    Joystick14 = ffi::GLFW_JOYSTICK_14,
3968    Joystick15 = ffi::GLFW_JOYSTICK_15,
3969    Joystick16 = ffi::GLFW_JOYSTICK_16,
3970}
3971
3972impl JoystickId {
3973    /// Converts from `i32`.
3974    pub fn from_i32(n: i32) -> Option<JoystickId> {
3975        if (0..=ffi::GLFW_JOYSTICK_LAST).contains(&n) {
3976            Some(unsafe { mem::transmute(n) })
3977        } else {
3978            None
3979        }
3980    }
3981}
3982
3983/// Button identifier tokens.
3984#[repr(i32)]
3985#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
3986#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3987pub enum GamepadButton {
3988    ButtonA = ffi::GLFW_GAMEPAD_BUTTON_A,
3989    ButtonB = ffi::GLFW_GAMEPAD_BUTTON_B,
3990    ButtonX = ffi::GLFW_GAMEPAD_BUTTON_X,
3991    ButtonY = ffi::GLFW_GAMEPAD_BUTTON_Y,
3992    ButtonLeftBumper = ffi::GLFW_GAMEPAD_BUTTON_LEFT_BUMPER,
3993    ButtonRightBumper = ffi::GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER,
3994    ButtonBack = ffi::GLFW_GAMEPAD_BUTTON_BACK,
3995    ButtonStart = ffi::GLFW_GAMEPAD_BUTTON_START,
3996    ButtonGuide = ffi::GLFW_GAMEPAD_BUTTON_GUIDE,
3997    ButtonLeftThumb = ffi::GLFW_GAMEPAD_BUTTON_LEFT_THUMB,
3998    ButtonRightThumb = ffi::GLFW_GAMEPAD_BUTTON_RIGHT_THUMB,
3999    ButtonDpadUp = ffi::GLFW_GAMEPAD_BUTTON_DPAD_UP,
4000    ButtonDpadRight = ffi::GLFW_GAMEPAD_BUTTON_DPAD_RIGHT,
4001    ButtonDpadDown = ffi::GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
4002    ButtonDpadLeft = ffi::GLFW_GAMEPAD_BUTTON_DPAD_LEFT,
4003}
4004
4005impl GamepadButton {
4006    /// Converts from `i32`.
4007    pub fn from_i32(n: i32) -> Option<GamepadButton> {
4008        if (0..=ffi::GLFW_GAMEPAD_BUTTON_LAST).contains(&n) {
4009            Some(unsafe { mem::transmute(n) })
4010        } else {
4011            None
4012        }
4013    }
4014}
4015
4016/// Axis identifier tokens.
4017#[repr(i32)]
4018#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
4019#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4020pub enum GamepadAxis {
4021    AxisLeftX = ffi::GLFW_GAMEPAD_AXIS_LEFT_X,
4022    AxisLeftY = ffi::GLFW_GAMEPAD_AXIS_LEFT_Y,
4023    AxisRightX = ffi::GLFW_GAMEPAD_AXIS_RIGHT_X,
4024    AxisRightY = ffi::GLFW_GAMEPAD_AXIS_RIGHT_Y,
4025    AxisLeftTrigger = ffi::GLFW_GAMEPAD_AXIS_LEFT_TRIGGER,
4026    AxisRightTrigger = ffi::GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER,
4027}
4028
4029impl GamepadAxis {
4030    /// Converts from `i32`.
4031    pub fn from_i32(n: i32) -> Option<GamepadAxis> {
4032        if (0..=ffi::GLFW_GAMEPAD_AXIS_LAST).contains(&n) {
4033            Some(unsafe { mem::transmute(n) })
4034        } else {
4035            None
4036        }
4037    }
4038}
4039
4040bitflags! {
4041    #[doc = "Joystick hats."]
4042    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4043    pub struct JoystickHats: ::std::os::raw::c_int {
4044        const Centered = crate::ffi::GLFW_HAT_CENTERED;
4045        const Up       = crate::ffi::GLFW_HAT_UP;
4046        const Right    = crate::ffi::GLFW_HAT_RIGHT;
4047        const Down     = crate::ffi::GLFW_HAT_DOWN;
4048        const Left     = crate::ffi::GLFW_HAT_LEFT;
4049    }
4050}
4051
4052/// A joystick handle.
4053#[derive(Clone, Debug)]
4054pub struct Joystick {
4055    pub id: JoystickId,
4056    pub glfw: Glfw,
4057}
4058
4059/// State of a gamepad.
4060#[derive(Copy, Clone, Debug)]
4061#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4062pub struct GamepadState {
4063    buttons: [Action; (ffi::GLFW_GAMEPAD_BUTTON_LAST + 1) as usize],
4064    axes: [f32; (ffi::GLFW_GAMEPAD_AXIS_LAST + 1) as usize],
4065}
4066
4067/// Joystick events.
4068#[repr(i32)]
4069#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
4070#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4071pub enum JoystickEvent {
4072    Connected = ffi::GLFW_CONNECTED,
4073    Disconnected = ffi::GLFW_DISCONNECTED,
4074}
4075
4076impl Joystick {
4077    /// Wrapper for `glfwJoystickPresent`.
4078    pub fn is_present(&self) -> bool {
4079        unsafe { ffi::glfwJoystickPresent(self.id as c_int) == ffi::GLFW_TRUE }
4080    }
4081
4082    /// Wrapper for `glfwGetJoystickAxes`.
4083    pub fn get_axes(&self) -> Vec<f32> {
4084        unsafe {
4085            let mut count = 0;
4086            let ptr = ffi::glfwGetJoystickAxes(self.id as c_int, &mut count);
4087            slice::from_raw_parts(ptr, count as usize)
4088                .iter()
4089                .map(|&a| a as f32)
4090                .collect()
4091        }
4092    }
4093
4094    /// Wrapper for `glfwGetJoystickButtons`.
4095    pub fn get_buttons(&self) -> Vec<c_int> {
4096        unsafe {
4097            let mut count = 0;
4098            let ptr = ffi::glfwGetJoystickButtons(self.id as c_int, &mut count);
4099            slice::from_raw_parts(ptr, count as usize)
4100                .iter()
4101                .map(|&b| b as c_int)
4102                .collect()
4103        }
4104    }
4105
4106    /// Wrapper for `glfwGetJoystickHats`.
4107    pub fn get_hats(&self) -> Vec<JoystickHats> {
4108        unsafe {
4109            let mut count = 0;
4110            let ptr = ffi::glfwGetJoystickHats(self.id as c_int, &mut count);
4111            slice::from_raw_parts(ptr, count as usize)
4112                .iter()
4113                .map(|&b| mem::transmute(b as c_int))
4114                .collect()
4115        }
4116    }
4117
4118    /// Wrapper for `glfwGetJoystickName`.
4119    pub fn get_name(&self) -> Option<String> {
4120        unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickName(self.id as c_int)) }
4121    }
4122
4123    /// Wrapper for `glfwGetJoystickGUID`.
4124    pub fn get_guid(&self) -> Option<String> {
4125        unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickGUID(self.id as c_int)) }
4126    }
4127
4128    /// Wrapper for `glfwJoystickIsGamepad`.
4129    pub fn is_gamepad(&self) -> bool {
4130        unsafe { ffi::glfwJoystickIsGamepad(self.id as c_int) == ffi::GLFW_TRUE }
4131    }
4132
4133    /// Wrapper for `glfwGetGamepadName`.
4134    pub fn get_gamepad_name(&self) -> Option<String> {
4135        unsafe { string_from_nullable_c_str(ffi::glfwGetGamepadName(self.id as c_int)) }
4136    }
4137
4138    /// Wrapper for `glfwGetGamepadState`.
4139    pub fn get_gamepad_state(&self) -> Option<GamepadState> {
4140        unsafe {
4141            let mut state = ffi::GLFWgamepadstate {
4142                buttons: [0; (ffi::GLFW_GAMEPAD_BUTTON_LAST + 1) as usize],
4143                axes: [0_f32; (ffi::GLFW_GAMEPAD_AXIS_LAST + 1) as usize],
4144            };
4145            if ffi::glfwGetGamepadState(self.id as c_int, &mut state) == ffi::GLFW_TRUE {
4146                Some(state.into())
4147            } else {
4148                None
4149            }
4150        }
4151    }
4152}
4153
4154impl From<ffi::GLFWgamepadstate> for GamepadState {
4155    fn from(state: ffi::GLFWgamepadstate) -> Self {
4156        let mut buttons = [Action::Release; (ffi::GLFW_GAMEPAD_BUTTON_LAST + 1) as usize];
4157        let mut axes = [0_f32; (ffi::GLFW_GAMEPAD_AXIS_LAST + 1) as usize];
4158        unsafe {
4159            state
4160                .buttons
4161                .iter()
4162                .map(|&b| mem::transmute(b as c_int))
4163                .zip(buttons.iter_mut())
4164                .for_each(|(a, b)| *b = a);
4165        }
4166        state
4167            .axes
4168            .iter()
4169            .map(|&f| f as f32)
4170            .zip(axes.iter_mut())
4171            .for_each(|(a, b)| *b = a);
4172        Self { buttons, axes }
4173    }
4174}
4175
4176impl GamepadState {
4177    pub fn get_button_state(&self, button: GamepadButton) -> Action {
4178        self.buttons[button as usize]
4179    }
4180
4181    pub fn get_axis(&self, axis: GamepadAxis) -> f32 {
4182        self.axes[axis as usize]
4183    }
4184}
4185
4186#[inline(always)]
4187fn unwrap_dont_care(value: Option<u32>) -> c_int {
4188    match value {
4189        Some(v) => v as c_int,
4190        None => ffi::GLFW_DONT_CARE,
4191    }
4192}