[go: up one dir, main page]

glfw/
lib.rs

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