Skip to main content

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