1#![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
33macro_rules! make_user_callback_functions {
85 (
86 doc -> $doc:literal,
87 set -> $set:ident,
88 unset -> $unset:ident,
89 poll -> $poll:ident,
90 callback_field -> $callback_field:ident,
91 poll_field -> $poll_field:ident,
92 glfw -> $glfw:ident,
93 args -> ($($args:ty),*),
94 secret -> $secret:ident
95 ) => {
96
97 #[doc = $doc]
98 pub fn $set<T>(&mut self, callback: T)
99 where T: FnMut(&mut Window, $($args),*) + 'static {
100 unsafe {
101 let callbacks = WindowCallbacks::get_callbacks(self.ptr);
102 callbacks.$callback_field = Some(Box::new(callback));
103 ffi::$glfw(self.ptr, Some(Self::$secret));
104 }
105 }
106
107 #[doc = $doc]
108 pub fn $unset(&mut self) {
109 unsafe {
110 let callbacks = WindowCallbacks::get_callbacks(self.ptr);
111 callbacks.$callback_field = None;
112
113 if !callbacks.$poll_field {
115 ffi::$glfw(self.ptr, None);
116 }
117 }
118 }
119
120 #[doc = $doc]
121 pub fn $poll(&mut self, should_poll: bool) {
122 unsafe {
123 let callbacks = WindowCallbacks::get_callbacks(self.ptr);
124 callbacks.$poll_field = should_poll;
125
126 if should_poll {
128 ffi::$glfw(self.ptr, Some(Self::$secret));
129 } else if callbacks.$callback_field.is_none() {
130 ffi::$glfw(self.ptr, None);
131 }
132 }
133 }
134 }
135}
136
137macro_rules! new_callback {
138 (
139 doc -> $doc:literal,
140 set -> $set:ident,
141 unset -> $unset:ident,
142 poll -> $poll:ident,
143 callback_field -> $callback_field:ident,
144 poll_field -> $poll_field:ident,
145 window_event -> $window_event:ident ($($args:ty),+),
146 glfw -> $glfw:ident ($($glfw_arg_names:ident: $glfw_args:ty),*),
147 convert_args -> ($($convert_args:expr),*),
148 secret -> $secret:ident
149 ) => {
150
151 #[allow(unused_unsafe)]
152 extern "C" fn $secret(glfw_window: *mut GLFWwindow, $($glfw_arg_names: $glfw_args),*) {
153 unsafe {
154 let callbacks = WindowCallbacks::get_callbacks(glfw_window);
155 let window = &mut *callbacks.window_ptr;
156 if let Some(func) = &mut callbacks.$callback_field {
157 func(window, $($convert_args),*);
158 }
159 if callbacks.$poll_field {
160 let event = (ffi::glfwGetTime() as f64, WindowEvent::$window_event($($convert_args),*));
161 if let Some(event) = callbacks::unbuffered::handle(glfw_window as WindowId, event) {
162 callbacks.sender.send(event);
163 }
164 }
165 }
166 }
167
168 make_user_callback_functions!(
169 doc -> $doc,
170 set -> $set,
171 unset -> $unset,
172 poll -> $poll,
173 callback_field -> $callback_field,
174 poll_field -> $poll_field,
175 glfw -> $glfw,
176 args -> ($($args),*),
177 secret -> $secret
178 );
179 };
180 (
181 doc -> $doc:literal,
182 set -> $set:ident,
183 unset -> $unset:ident,
184 poll -> $poll:ident,
185 callback_field -> $callback_field:ident,
186 poll_field -> $poll_field:ident,
187 window_event -> $window_event:ident,
188 glfw -> $glfw:ident ($($glfw_arg_names:ident: $glfw_args:ty),*),
189 convert_args -> ($($convert_args:expr),*),
190 secret -> $secret:ident
191 ) => {
192
193 #[allow(unused_unsafe)]
194 extern "C" fn $secret(glfw_window: *mut GLFWwindow, $($glfw_arg_names: $glfw_args),*) {
195 unsafe {
196 let callbacks = WindowCallbacks::get_callbacks(glfw_window);
197 let window = &mut *callbacks.window_ptr;
198 if let Some(func) = &mut callbacks.$callback_field {
199 func(window);
200 }
201 if callbacks.$poll_field {
202 let event = (ffi::glfwGetTime() as f64, WindowEvent::$window_event);
203 if let Some(event) = callbacks::unbuffered::handle(glfw_window as WindowId, event) {
204 callbacks.sender.send(event);
205 }
206 }
207 }
208 }
209
210 make_user_callback_functions!(
211 doc -> $doc,
212 set -> $set,
213 unset -> $unset,
214 poll -> $poll,
215 callback_field -> $callback_field,
216 poll_field -> $poll_field,
217 glfw -> $glfw,
218 args -> (),
219 secret -> $secret
220 );
221 }
222}
223
224#[cfg(feature = "log")]
225#[macro_use]
226extern crate log;
227#[macro_use]
228extern crate bitflags;
229#[cfg(feature = "image")]
230extern crate image;
231
232#[cfg(feature = "raw-window-handle-v0-6")]
233extern crate raw_window_handle_0_6 as raw_window_handle;
234
235#[cfg(feature = "raw-window-handle-v0-5")]
236extern crate raw_window_handle_0_5 as raw_window_handle;
237
238use std::collections::VecDeque;
239#[allow(unused)]
240use std::ffi::*;
241use std::ffi::{CStr, CString};
242use std::marker::Send;
243use std::ops::{Deref, DerefMut};
244#[cfg(feature = "vulkan")]
245use std::os::raw::c_uint;
246#[cfg(not(target_os = "emscripten"))]
247use std::os::raw::c_void;
248use std::os::raw::{c_char, c_double, c_float, c_int, c_uchar, c_ushort};
249use std::path::PathBuf;
250use std::ptr::{null, null_mut};
251use std::sync::atomic::{AtomicUsize, Ordering};
252use std::sync::mpsc::{channel, Receiver, Sender};
253use std::sync::{Arc, Mutex};
254use std::{error, fmt, mem, ptr, slice};
255
256#[cfg(feature = "vulkan")]
257use ash::vk;
258#[cfg(feature = "raw-window-handle-v0-6")]
259use raw_window_handle::{
260 DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
261};
262#[cfg(feature = "raw-window-handle-v0-5")]
263use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
264use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
265#[cfg(feature = "serde")]
266use serde::{Deserialize, Serialize};
267
268pub use self::MouseButton::Button1 as MouseButtonLeft;
270pub use self::MouseButton::Button2 as MouseButtonRight;
272pub use self::MouseButton::Button3 as MouseButtonMiddle;
274use crate::ffi::GLFWwindow;
275
276mod callbacks;
277pub mod ffi;
278
279#[derive(Debug)]
280#[repr(transparent)]
281pub struct PWindow(Box<Window>);
282
283impl PWindow {
284 fn raw_ptr(&mut self) -> *mut Window {
285 self.0.deref_mut()
286 }
287}
288
289impl Deref for PWindow {
290 type Target = Window;
291 fn deref(&self) -> &Self::Target {
292 self.0.deref()
293 }
294}
295
296impl DerefMut for PWindow {
297 fn deref_mut(&mut self) -> &mut Self::Target {
298 self.0.deref_mut()
299 }
300}
301
302unsafe impl Send for PWindow {}
303
304unsafe impl Sync for PWindow {}
305
306#[cfg(feature = "raw-window-handle-v0-6")]
308impl HasWindowHandle for PWindow {
309 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
310 self.0.window_handle()
311 }
312}
313
314#[cfg(feature = "raw-window-handle-v0-6")]
315impl HasDisplayHandle for PWindow {
316 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
317 self.0.display_handle()
318 }
319}
320
321pub type WindowId = usize;
323
324#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
325#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
326pub struct Version {
327 pub major: u64,
328 pub minor: u64,
329 pub patch: u64,
330}
331
332#[repr(i32)]
334#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
335#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
336pub enum Action {
337 Release = ffi::RELEASE,
338 Press = ffi::PRESS,
339 Repeat = ffi::REPEAT,
340}
341
342#[repr(i32)]
344#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
345#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
346pub enum Key {
347 Space = ffi::KEY_SPACE,
348 Apostrophe = ffi::KEY_APOSTROPHE,
349 Comma = ffi::KEY_COMMA,
350 Minus = ffi::KEY_MINUS,
351 Period = ffi::KEY_PERIOD,
352 Slash = ffi::KEY_SLASH,
353 Num0 = ffi::KEY_0,
354 Num1 = ffi::KEY_1,
355 Num2 = ffi::KEY_2,
356 Num3 = ffi::KEY_3,
357 Num4 = ffi::KEY_4,
358 Num5 = ffi::KEY_5,
359 Num6 = ffi::KEY_6,
360 Num7 = ffi::KEY_7,
361 Num8 = ffi::KEY_8,
362 Num9 = ffi::KEY_9,
363 Semicolon = ffi::KEY_SEMICOLON,
364 Equal = ffi::KEY_EQUAL,
365 A = ffi::KEY_A,
366 B = ffi::KEY_B,
367 C = ffi::KEY_C,
368 D = ffi::KEY_D,
369 E = ffi::KEY_E,
370 F = ffi::KEY_F,
371 G = ffi::KEY_G,
372 H = ffi::KEY_H,
373 I = ffi::KEY_I,
374 J = ffi::KEY_J,
375 K = ffi::KEY_K,
376 L = ffi::KEY_L,
377 M = ffi::KEY_M,
378 N = ffi::KEY_N,
379 O = ffi::KEY_O,
380 P = ffi::KEY_P,
381 Q = ffi::KEY_Q,
382 R = ffi::KEY_R,
383 S = ffi::KEY_S,
384 T = ffi::KEY_T,
385 U = ffi::KEY_U,
386 V = ffi::KEY_V,
387 W = ffi::KEY_W,
388 X = ffi::KEY_X,
389 Y = ffi::KEY_Y,
390 Z = ffi::KEY_Z,
391 LeftBracket = ffi::KEY_LEFT_BRACKET,
392 Backslash = ffi::KEY_BACKSLASH,
393 RightBracket = ffi::KEY_RIGHT_BRACKET,
394 GraveAccent = ffi::KEY_GRAVE_ACCENT,
395 World1 = ffi::KEY_WORLD_1,
396 World2 = ffi::KEY_WORLD_2,
397
398 Escape = ffi::KEY_ESCAPE,
399 Enter = ffi::KEY_ENTER,
400 Tab = ffi::KEY_TAB,
401 Backspace = ffi::KEY_BACKSPACE,
402 Insert = ffi::KEY_INSERT,
403 Delete = ffi::KEY_DELETE,
404 Right = ffi::KEY_RIGHT,
405 Left = ffi::KEY_LEFT,
406 Down = ffi::KEY_DOWN,
407 Up = ffi::KEY_UP,
408 PageUp = ffi::KEY_PAGE_UP,
409 PageDown = ffi::KEY_PAGE_DOWN,
410 Home = ffi::KEY_HOME,
411 End = ffi::KEY_END,
412 CapsLock = ffi::KEY_CAPS_LOCK,
413 ScrollLock = ffi::KEY_SCROLL_LOCK,
414 NumLock = ffi::KEY_NUM_LOCK,
415 PrintScreen = ffi::KEY_PRINT_SCREEN,
416 Pause = ffi::KEY_PAUSE,
417 F1 = ffi::KEY_F1,
418 F2 = ffi::KEY_F2,
419 F3 = ffi::KEY_F3,
420 F4 = ffi::KEY_F4,
421 F5 = ffi::KEY_F5,
422 F6 = ffi::KEY_F6,
423 F7 = ffi::KEY_F7,
424 F8 = ffi::KEY_F8,
425 F9 = ffi::KEY_F9,
426 F10 = ffi::KEY_F10,
427 F11 = ffi::KEY_F11,
428 F12 = ffi::KEY_F12,
429 F13 = ffi::KEY_F13,
430 F14 = ffi::KEY_F14,
431 F15 = ffi::KEY_F15,
432 F16 = ffi::KEY_F16,
433 F17 = ffi::KEY_F17,
434 F18 = ffi::KEY_F18,
435 F19 = ffi::KEY_F19,
436 F20 = ffi::KEY_F20,
437 F21 = ffi::KEY_F21,
438 F22 = ffi::KEY_F22,
439 F23 = ffi::KEY_F23,
440 F24 = ffi::KEY_F24,
441 F25 = ffi::KEY_F25,
442 Kp0 = ffi::KEY_KP_0,
443 Kp1 = ffi::KEY_KP_1,
444 Kp2 = ffi::KEY_KP_2,
445 Kp3 = ffi::KEY_KP_3,
446 Kp4 = ffi::KEY_KP_4,
447 Kp5 = ffi::KEY_KP_5,
448 Kp6 = ffi::KEY_KP_6,
449 Kp7 = ffi::KEY_KP_7,
450 Kp8 = ffi::KEY_KP_8,
451 Kp9 = ffi::KEY_KP_9,
452 KpDecimal = ffi::KEY_KP_DECIMAL,
453 KpDivide = ffi::KEY_KP_DIVIDE,
454 KpMultiply = ffi::KEY_KP_MULTIPLY,
455 KpSubtract = ffi::KEY_KP_SUBTRACT,
456 KpAdd = ffi::KEY_KP_ADD,
457 KpEnter = ffi::KEY_KP_ENTER,
458 KpEqual = ffi::KEY_KP_EQUAL,
459 LeftShift = ffi::KEY_LEFT_SHIFT,
460 LeftControl = ffi::KEY_LEFT_CONTROL,
461 LeftAlt = ffi::KEY_LEFT_ALT,
462 LeftSuper = ffi::KEY_LEFT_SUPER,
463 RightShift = ffi::KEY_RIGHT_SHIFT,
464 RightControl = ffi::KEY_RIGHT_CONTROL,
465 RightAlt = ffi::KEY_RIGHT_ALT,
466 RightSuper = ffi::KEY_RIGHT_SUPER,
467 Menu = ffi::KEY_MENU,
468 Unknown = ffi::KEY_UNKNOWN,
469}
470
471pub fn get_key_name(key: Option<Key>, scancode: Option<Scancode>) -> Option<String> {
473 unsafe {
474 string_from_nullable_c_str(ffi::glfwGetKeyName(
475 match key {
476 Some(k) => k as c_int,
477 None => ffi::KEY_UNKNOWN,
478 },
479 scancode.unwrap_or(ffi::KEY_UNKNOWN),
480 ))
481 }
482}
483
484#[deprecated(
486 since = "0.16.0",
487 note = "'key_name' can cause a segfault, use 'get_key_name' instead"
488)]
489pub fn key_name(key: Option<Key>, scancode: Option<Scancode>) -> String {
490 unsafe {
491 string_from_c_str(ffi::glfwGetKeyName(
492 match key {
493 Some(k) => k as c_int,
494 None => ffi::KEY_UNKNOWN,
495 },
496 scancode.unwrap_or(ffi::KEY_UNKNOWN),
497 ))
498 }
499}
500
501pub fn get_key_scancode(key: Option<Key>) -> Option<Scancode> {
503 unsafe {
504 match ffi::glfwGetKeyScancode(match key {
505 Some(key) => key as c_int,
506 None => ffi::KEY_UNKNOWN,
507 }) {
508 ffi::KEY_UNKNOWN => None,
509 scancode => Some(scancode as Scancode),
510 }
511 }
512}
513
514impl Key {
515 #[deprecated(
517 since = "0.16.0",
518 note = "Key method 'name' can cause a segfault, use 'get_name' instead"
519 )]
520 pub fn name(&self) -> String {
521 #[allow(deprecated)]
522 key_name(Some(*self), None)
523 }
524
525 pub fn get_name(&self) -> Option<String> {
527 get_key_name(Some(*self), None)
528 }
529
530 pub fn get_scancode(&self) -> Option<Scancode> {
532 get_key_scancode(Some(*self))
533 }
534}
535
536#[repr(i32)]
539#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
540#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
541pub enum MouseButton {
542 Button1 = ffi::MOUSE_BUTTON_1,
544 Button2 = ffi::MOUSE_BUTTON_2,
546 Button3 = ffi::MOUSE_BUTTON_3,
548 Button4 = ffi::MOUSE_BUTTON_4,
549 Button5 = ffi::MOUSE_BUTTON_5,
550 Button6 = ffi::MOUSE_BUTTON_6,
551 Button7 = ffi::MOUSE_BUTTON_7,
552 Button8 = ffi::MOUSE_BUTTON_8,
553}
554
555impl MouseButton {
556 pub const Left: Self = MouseButton::Button1;
558 pub const Right: Self = MouseButton::Button2;
560 pub const Middle: Self = MouseButton::Button3;
562
563 pub fn from_i32(n: i32) -> Option<MouseButton> {
565 if (0..=ffi::MOUSE_BUTTON_LAST).contains(&n) {
566 Some(unsafe { mem::transmute(n) })
567 } else {
568 None
569 }
570 }
571}
572
573pub struct DebugAliases<T>(pub T);
582
583impl fmt::Debug for DebugAliases<MouseButton> {
584 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585 let DebugAliases(button) = *self;
586 match button {
587 MouseButtonLeft => write!(f, "MouseButtonLeft"),
588 MouseButtonRight => write!(f, "MouseButtonRight"),
589 MouseButtonMiddle => write!(f, "MouseButtonMiddle"),
590 button => button.fmt(f),
591 }
592 }
593}
594
595#[repr(i32)]
597#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
598#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
599pub enum Error {
600 NoError = ffi::NO_ERROR,
601 NotInitialized = ffi::NOT_INITIALIZED,
602 NoCurrentContext = ffi::NO_CURRENT_CONTEXT,
603 InvalidEnum = ffi::INVALID_ENUM,
604 InvalidValue = ffi::INVALID_VALUE,
605 OutOfMemory = ffi::OUT_OF_MEMORY,
606 ApiUnavailable = ffi::API_UNAVAILABLE,
607 VersionUnavailable = ffi::VERSION_UNAVAILABLE,
608 PlatformError = ffi::PLATFORM_ERROR,
609 FormatUnavailable = ffi::FORMAT_UNAVAILABLE,
610 NoWindowContext = ffi::NO_WINDOW_CONTEXT,
611}
612
613impl fmt::Display for Error {
614 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
615 let description = match *self {
616 Error::NoError => "NoError",
617 Error::NotInitialized => "NotInitialized",
618 Error::NoCurrentContext => "NoCurrentContext",
619 Error::InvalidEnum => "InvalidEnum",
620 Error::InvalidValue => "InvalidValue",
621 Error::OutOfMemory => "OutOfMemory",
622 Error::ApiUnavailable => "ApiUnavailable",
623 Error::VersionUnavailable => "VersionUnavailable",
624 Error::PlatformError => "PlatformError",
625 Error::FormatUnavailable => "FormatUnavailable",
626 Error::NoWindowContext => "NoWindowContext",
627 };
628
629 f.write_str(description)
630 }
631}
632
633impl error::Error for Error {}
634
635pub fn fail_on_errors(_: Error, description: String) {
637 panic!("GLFW Error: {}", description);
638}
639
640#[macro_export]
642macro_rules! fail_on_errors {
643 () => {{
644 |error, description| {
645 fail_on_errors(error, description);
646 }
647 }};
648}
649
650#[cfg(feature = "log")]
651pub fn log_errors(_: Error, description: String) {
653 error!("GLFW Error: {}", description);
654}
655
656#[cfg(not(feature = "log"))]
657pub fn log_errors(_: Error, description: String) {
659 eprintln!("GLFW Error: {}", description);
660}
661
662#[macro_export]
665macro_rules! log_errors {
666 () => {{
667 |error, description| {
668 log_errors(error, description);
669 }
670 }};
671}
672
673#[derive(Debug)]
676pub struct PixelImage {
677 pub width: u32,
679 pub height: u32,
681 pub pixels: Vec<u32>,
683}
684
685#[repr(i32)]
687#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
688#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
689pub enum CursorMode {
690 Normal = ffi::CURSOR_NORMAL,
691 Hidden = ffi::CURSOR_HIDDEN,
692 Disabled = ffi::CURSOR_DISABLED,
693}
694
695#[repr(i32)]
697#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
698#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
699pub enum StandardCursor {
700 Arrow = ffi::ARROW_CURSOR,
702 IBeam = ffi::IBEAM_CURSOR,
704 Crosshair = ffi::CROSSHAIR_CURSOR,
706 Hand = ffi::HAND_CURSOR,
708 HResize = ffi::HRESIZE_CURSOR,
710 VResize = ffi::VRESIZE_CURSOR,
712}
713
714#[derive(Debug)]
720pub struct Cursor {
721 ptr: *mut ffi::GLFWcursor,
722}
723
724impl Drop for Cursor {
725 fn drop(&mut self) {
726 unsafe { ffi::glfwDestroyCursor(self.ptr) }
727 }
728}
729
730impl Cursor {
731 pub fn standard(cursor: StandardCursor) -> Cursor {
733 Cursor {
734 ptr: unsafe { ffi::glfwCreateStandardCursor(cursor as c_int) },
735 }
736 }
737
738 #[cfg(feature = "image")]
747 pub fn create(image: image::RgbaImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
748 let (width, height) = image.dimensions();
749
750 let image_data = image.into_vec();
751
752 let glfw_image = ffi::GLFWimage {
753 width: width as c_int,
754 height: height as c_int,
755 pixels: image_data.as_ptr() as *const c_uchar,
756 };
757
758 Cursor {
759 ptr: unsafe {
760 ffi::glfwCreateCursor(
761 &glfw_image as *const ffi::GLFWimage,
762 x_hotspot as c_int,
763 y_hotspot as c_int,
764 )
765 },
766 }
767 }
768
769 pub fn create_from_pixels(image: PixelImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
778 let glfw_image = ffi::GLFWimage {
779 width: image.width as c_int,
780 height: image.height as c_int,
781 pixels: image.pixels.as_ptr() as *const c_uchar,
782 };
783
784 Cursor {
785 ptr: unsafe {
786 ffi::glfwCreateCursor(
787 &glfw_image as *const ffi::GLFWimage,
788 x_hotspot as c_int,
789 y_hotspot as c_int,
790 )
791 },
792 }
793 }
794}
795
796#[derive(Copy, Clone)]
798#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
799pub struct VidMode {
800 pub width: u32,
801 pub height: u32,
802 pub red_bits: u32,
803 pub green_bits: u32,
804 pub blue_bits: u32,
805 pub refresh_rate: u32,
806}
807
808#[derive(Debug)]
810#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
811pub struct GammaRamp {
812 pub red: Vec<c_ushort>,
813 pub green: Vec<c_ushort>,
814 pub blue: Vec<c_ushort>,
815}
816
817#[repr(i32)]
819#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
820#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
821pub enum ContextReleaseBehavior {
822 Any = ffi::ANY_RELEASE_BEHAVIOR,
823 Flush = ffi::RELEASE_BEHAVIOR_FLUSH,
826 None = ffi::RELEASE_BEHAVIOR_NONE,
828}
829
830#[repr(i32)]
832#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
833#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
834pub enum ContextCreationApi {
835 Native = ffi::NATIVE_CONTEXT_API,
836 Egl = ffi::EGL_CONTEXT_API,
837 OsMesa = ffi::OSMESA_CONTEXT_API,
838}
839
840#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
846#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
847pub enum SwapInterval {
848 None,
850 Adaptive,
853 Sync(u32),
855}
856
857pub type GLProc = ffi::GLFWglproc;
859
860#[cfg(feature = "vulkan")]
862pub type VkProc = ffi::GLFWvkproc;
863
864static REF_COUNT_FOR_GLFW: AtomicUsize = AtomicUsize::new(0);
867
868#[derive(Debug)]
870pub struct ThreadSafeGlfw {
871 glfw: Glfw,
872}
873
874impl ThreadSafeGlfw {
875 pub fn from(glfw: &mut Glfw) -> Self {
877 Self { glfw: glfw.clone() }
878 }
879
880 pub fn set_swap_interval(&mut self, interval: SwapInterval) {
882 self.glfw.set_swap_interval(interval);
883 }
884
885 pub fn extension_supported(&self, extension: &str) -> bool {
887 self.glfw.extension_supported(extension)
888 }
889
890 pub fn get_time(&self) -> f64 {
892 self.glfw.get_time()
893 }
894
895 pub fn set_time(&mut self, time: f64) {
897 self.glfw.set_time(time);
898 }
899
900 #[cfg(feature = "vulkan")]
902 pub fn vulkan_supported(&self) -> bool {
903 self.glfw.vulkan_supported()
904 }
905
906 #[cfg(feature = "vulkan")]
908 pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
909 self.glfw.get_required_instance_extensions()
910 }
911
912 #[cfg(feature = "vulkan")]
914 pub fn get_instance_proc_address_raw(&self, instance: vk::Instance, procname: &str) -> VkProc {
915 self.glfw.get_instance_proc_address_raw(instance, procname)
916 }
917
918 #[cfg(feature = "vulkan")]
920 pub fn get_physical_device_presentation_support_raw(
921 &self,
922 instance: vk::Instance,
923 device: vk::PhysicalDevice,
924 queue_family: u32,
925 ) -> bool {
926 self.glfw
927 .get_physical_device_presentation_support_raw(instance, device, queue_family)
928 }
929
930 pub fn get_timer_value(&self) -> u64 {
932 self.glfw.get_timer_value()
933 }
934
935 pub fn get_timer_frequency(&self) -> u64 {
937 self.glfw.get_timer_frequency()
938 }
939
940 pub fn post_empty_event(&self) {
942 self.glfw.post_empty_event()
943 }
944}
945
946unsafe impl Send for ThreadSafeGlfw {}
947
948#[non_exhaustive]
954#[derive(Debug)]
955pub struct Glfw {
956 phantom: std::marker::PhantomData<*const ()>,
957}
958
959#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
961#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
962pub enum InitError {
963 AlreadyInitialized,
965 Internal,
967}
968
969impl fmt::Display for InitError {
970 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
971 let description = match *self {
972 InitError::AlreadyInitialized => "Already Initialized",
973 InitError::Internal => "Internal Initialization Error",
974 };
975
976 f.write_str(description)
977 }
978}
979
980impl error::Error for InitError {}
981
982#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
984#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
985pub enum InitHint {
986 JoystickHatButtons(bool),
989 CocoaChdirResources(bool),
994 CocoaMenubar(bool),
999}
1000
1001pub fn init_hint(hint: InitHint) {
1009 match hint {
1010 InitHint::JoystickHatButtons(joystick_hat_buttons) => unsafe {
1011 ffi::glfwInitHint(ffi::JOYSTICK_HAT_BUTTONS, joystick_hat_buttons as c_int)
1012 },
1013 InitHint::CocoaChdirResources(chdir) => unsafe {
1014 ffi::glfwInitHint(ffi::COCOA_CHDIR_RESOURCES, chdir as c_int)
1015 },
1016 InitHint::CocoaMenubar(menubar) => unsafe {
1017 ffi::glfwInitHint(ffi::COCOA_MENUBAR, menubar as c_int)
1018 },
1019 }
1020}
1021pub fn init<T>(callback: T) -> Result<Glfw, InitError>
1064where
1065 T: FnMut(Error, String) + 'static,
1066{
1067 callbacks::error::set(callback);
1071
1072 init_no_callbacks()
1073}
1074
1075pub fn init_no_callbacks() -> Result<Glfw, InitError> {
1076 if unsafe { ffi::glfwInit() } == ffi::TRUE {
1080 REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
1081 Ok(Glfw {
1082 phantom: std::marker::PhantomData,
1083 })
1084 } else {
1085 Err(InitError::Internal)
1086 }
1087}
1088
1089impl Glfw {
1090 pub fn set_error_callback<T>(&mut self, callback: T)
1114 where
1115 T: FnMut(Error, String) + 'static,
1116 {
1117 callbacks::error::set(callback);
1118 }
1119
1120 pub fn unset_error_callback(&mut self) {
1122 callbacks::error::unset();
1123 }
1124
1125 pub fn set_monitor_callback<T>(&mut self, callback: T)
1127 where
1128 T: FnMut(Monitor, MonitorEvent) + 'static,
1129 {
1130 callbacks::monitor::set(callback);
1131 }
1132
1133 pub fn unset_monitor_callback(&mut self) {
1135 callbacks::monitor::unset();
1136 }
1137
1138 pub fn set_joystick_callback<T>(&mut self, callback: T)
1140 where
1141 T: FnMut(JoystickId, JoystickEvent) + 'static,
1142 {
1143 callbacks::joystick::set(callback);
1144 }
1145
1146 pub fn unset_joystick_callback(&mut self) {
1148 callbacks::joystick::unset();
1149 }
1150
1151 pub fn with_primary_monitor<T, F>(&mut self, f: F) -> T
1164 where
1165 F: FnOnce(&mut Self, Option<&mut Monitor>) -> T,
1166 {
1167 match unsafe { ffi::glfwGetPrimaryMonitor() } {
1168 ptr if ptr.is_null() => f(self, None),
1169 ptr => f(self, Some(&mut Monitor { ptr })),
1170 }
1171 }
1172
1173 pub fn with_window_monitor<T, F>(&mut self, window: &mut Window, f: F) -> T
1184 where
1185 F: FnOnce(&mut Self, Option<&mut Monitor>) -> T,
1186 {
1187 match unsafe { ffi::glfwGetWindowMonitor(window.ptr) } {
1188 ptr if ptr.is_null() => f(self, None),
1189 ptr => f(self, Some(&mut Monitor { ptr })),
1190 }
1191 }
1192
1193 pub fn with_connected_monitors<T, F>(&mut self, f: F) -> T
1206 where
1207 F: FnOnce(&mut Self, &[&mut Monitor]) -> T,
1208 {
1209 unsafe {
1210 let mut count = 0;
1211 let ptr = ffi::glfwGetMonitors(&mut count);
1212 let mut monitors = slice::from_raw_parts(ptr as *const _, count as usize)
1213 .iter()
1214 .map(|&ptr| Monitor { ptr })
1215 .collect::<Vec<Monitor>>();
1216
1217 let refs: Vec<&mut Monitor> = monitors.iter_mut().collect();
1218 f(self, &refs)
1219 }
1220 }
1221
1222 #[cfg(feature = "vulkan")]
1224 pub fn vulkan_supported(&self) -> bool {
1225 unsafe { ffi::glfwVulkanSupported() == ffi::TRUE }
1226 }
1227
1228 pub fn window_hint(&mut self, hint: WindowHint) {
1258 #[inline(always)]
1263 unsafe fn dont_care_hint(hint: c_int, value: Option<u32>) {
1264 ffi::glfwWindowHint(hint, unwrap_dont_care(value))
1265 }
1266
1267 #[inline(always)]
1268 unsafe fn string_hint(hint: c_int, value: Option<String>) {
1269 let value = if let Some(value) = &value {
1270 value.as_str()
1271 } else {
1272 ""
1273 };
1274 with_c_str(value, |value| ffi::glfwWindowHintString(hint, value))
1275 }
1276
1277 match hint {
1278 WindowHint::RedBits(bits) => unsafe { dont_care_hint(ffi::RED_BITS, bits) },
1279 WindowHint::GreenBits(bits) => unsafe { dont_care_hint(ffi::GREEN_BITS, bits) },
1280 WindowHint::BlueBits(bits) => unsafe { dont_care_hint(ffi::BLUE_BITS, bits) },
1281 WindowHint::AlphaBits(bits) => unsafe { dont_care_hint(ffi::ALPHA_BITS, bits) },
1282 WindowHint::DepthBits(bits) => unsafe { dont_care_hint(ffi::DEPTH_BITS, bits) },
1283 WindowHint::StencilBits(bits) => unsafe { dont_care_hint(ffi::STENCIL_BITS, bits) },
1284 WindowHint::AccumRedBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_RED_BITS, bits) },
1285 WindowHint::AccumGreenBits(bits) => unsafe {
1286 dont_care_hint(ffi::ACCUM_GREEN_BITS, bits)
1287 },
1288 WindowHint::AccumBlueBits(bits) => unsafe {
1289 dont_care_hint(ffi::ACCUM_BLUE_BITS, bits)
1290 },
1291 WindowHint::AccumAlphaBits(bits) => unsafe {
1292 dont_care_hint(ffi::ACCUM_ALPHA_BITS, bits)
1293 },
1294 WindowHint::AuxBuffers(num_buffers) => unsafe {
1295 dont_care_hint(ffi::AUX_BUFFERS, num_buffers)
1296 },
1297 WindowHint::Samples(num_samples) => unsafe {
1298 dont_care_hint(ffi::SAMPLES, num_samples)
1299 },
1300 WindowHint::RefreshRate(rate) => unsafe { dont_care_hint(ffi::REFRESH_RATE, rate) },
1301 WindowHint::Stereo(is_stereo) => unsafe {
1302 ffi::glfwWindowHint(ffi::STEREO, is_stereo as c_int)
1303 },
1304 WindowHint::SRgbCapable(is_capable) => unsafe {
1305 ffi::glfwWindowHint(ffi::SRGB_CAPABLE, is_capable as c_int)
1306 },
1307 WindowHint::ClientApi(api) => unsafe {
1308 ffi::glfwWindowHint(ffi::CLIENT_API, api as c_int)
1309 },
1310 WindowHint::ContextVersionMajor(major) => unsafe {
1311 ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MAJOR, major as c_int)
1312 },
1313 WindowHint::ContextVersionMinor(minor) => unsafe {
1314 ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MINOR, minor as c_int)
1315 },
1316 WindowHint::ContextVersion(major, minor) => unsafe {
1317 ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MAJOR, major as c_int);
1318 ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MINOR, minor as c_int)
1319 },
1320 WindowHint::ContextRobustness(robustness) => unsafe {
1321 ffi::glfwWindowHint(ffi::CONTEXT_ROBUSTNESS, robustness as c_int)
1322 },
1323 WindowHint::OpenGlForwardCompat(is_compat) => unsafe {
1324 ffi::glfwWindowHint(ffi::OPENGL_FORWARD_COMPAT, is_compat as c_int)
1325 },
1326 WindowHint::OpenGlDebugContext(is_debug) => unsafe {
1327 ffi::glfwWindowHint(ffi::OPENGL_DEBUG_CONTEXT, is_debug as c_int)
1328 },
1329 WindowHint::OpenGlProfile(profile) => unsafe {
1330 ffi::glfwWindowHint(ffi::OPENGL_PROFILE, profile as c_int)
1331 },
1332 WindowHint::Resizable(is_resizable) => unsafe {
1333 ffi::glfwWindowHint(ffi::RESIZABLE, is_resizable as c_int)
1334 },
1335 WindowHint::Visible(is_visible) => unsafe {
1336 ffi::glfwWindowHint(ffi::VISIBLE, is_visible as c_int)
1337 },
1338 WindowHint::Decorated(is_decorated) => unsafe {
1339 ffi::glfwWindowHint(ffi::DECORATED, is_decorated as c_int)
1340 },
1341 WindowHint::AutoIconify(auto_iconify) => unsafe {
1342 ffi::glfwWindowHint(ffi::AUTO_ICONIFY, auto_iconify as c_int)
1343 },
1344 WindowHint::Floating(is_floating) => unsafe {
1345 ffi::glfwWindowHint(ffi::FLOATING, is_floating as c_int)
1346 },
1347 WindowHint::Focused(is_focused) => unsafe {
1348 ffi::glfwWindowHint(ffi::FOCUSED, is_focused as c_int)
1349 },
1350 WindowHint::Maximized(is_maximized) => unsafe {
1351 ffi::glfwWindowHint(ffi::MAXIMIZED, is_maximized as c_int)
1352 },
1353 WindowHint::ContextNoError(is_no_error) => unsafe {
1354 ffi::glfwWindowHint(ffi::CONTEXT_NO_ERROR, is_no_error as c_int)
1355 },
1356 WindowHint::ContextCreationApi(api) => unsafe {
1357 ffi::glfwWindowHint(ffi::CONTEXT_CREATION_API, api as c_int)
1358 },
1359 WindowHint::ContextReleaseBehavior(behavior) => unsafe {
1360 ffi::glfwWindowHint(ffi::CONTEXT_RELEASE_BEHAVIOR, behavior as c_int)
1361 },
1362 WindowHint::DoubleBuffer(is_dbuffered) => unsafe {
1363 ffi::glfwWindowHint(ffi::DOUBLEBUFFER, is_dbuffered as c_int)
1364 },
1365 WindowHint::CenterCursor(center_cursor) => unsafe {
1366 ffi::glfwWindowHint(ffi::CENTER_CURSOR, center_cursor as c_int)
1367 },
1368 WindowHint::TransparentFramebuffer(is_transparent) => unsafe {
1369 ffi::glfwWindowHint(ffi::TRANSPARENT_FRAMEBUFFER, is_transparent as c_int)
1370 },
1371 WindowHint::FocusOnShow(focus) => unsafe {
1372 ffi::glfwWindowHint(ffi::FOCUS_ON_SHOW, focus as c_int)
1373 },
1374 WindowHint::ScaleToMonitor(scale) => unsafe {
1375 ffi::glfwWindowHint(ffi::SCALE_TO_MONITOR, scale as c_int)
1376 },
1377 WindowHint::CocoaRetinaFramebuffer(retina_fb) => unsafe {
1378 ffi::glfwWindowHint(ffi::COCOA_RETINA_FRAMEBUFFER, retina_fb as c_int)
1379 },
1380 WindowHint::CocoaFrameName(name) => unsafe { string_hint(ffi::COCOA_FRAME_NAME, name) },
1381 WindowHint::CocoaGraphicsSwitching(graphics_switching) => unsafe {
1382 ffi::glfwWindowHint(ffi::COCOA_GRAPHICS_SWITCHING, graphics_switching as c_int)
1383 },
1384 WindowHint::X11ClassName(class_name) => unsafe {
1385 string_hint(ffi::X11_CLASS_NAME, class_name)
1386 },
1387 WindowHint::X11InstanceName(instance_name) => unsafe {
1388 string_hint(ffi::X11_INSTANCE_NAME, instance_name)
1389 },
1390 }
1391 }
1392
1393 pub fn default_window_hints(&mut self) {
1398 unsafe {
1399 ffi::glfwDefaultWindowHints();
1400 }
1401 }
1402
1403 pub fn create_window(
1407 &mut self,
1408 width: u32,
1409 height: u32,
1410 title: &str,
1411 mode: WindowMode<'_>,
1412 ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
1413 #[cfg(feature = "wayland")]
1414 {
1415 self.window_hint(WindowHint::Focused(false));
1417 }
1418 self.create_window_intern(width, height, title, mode, None)
1419 }
1420
1421 fn create_window_intern(
1423 &self,
1424 width: u32,
1425 height: u32,
1426 title: &str,
1427 mode: WindowMode<'_>,
1428 share: Option<&Window>,
1429 ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
1430 let ptr = unsafe {
1431 with_c_str(title, |title| {
1432 ffi::glfwCreateWindow(
1433 width as c_int,
1434 height as c_int,
1435 title,
1436 mode.to_ptr(),
1437 match share {
1438 Some(w) => w.ptr,
1439 None => ptr::null_mut(),
1440 },
1441 )
1442 })
1443 };
1444 if ptr.is_null() {
1445 None
1446 } else {
1447 let (drop_sender, drop_receiver) = channel();
1448 let (sender, receiver) = glfw_channel(16, 256);
1449 let window = Window {
1450 ptr,
1451 glfw: self.clone(),
1452 is_shared: share.is_some(),
1453 drop_sender: Some(drop_sender),
1454 drop_receiver,
1455 current_cursor: None,
1456 };
1457 let mut callbacks = Box::new(WindowCallbacks::new(sender));
1458 let mut window = PWindow(Box::new(window));
1459
1460 unsafe {
1461 callbacks.window_ptr = window.raw_ptr();
1462 ffi::glfwSetWindowUserPointer(ptr, mem::transmute(callbacks));
1463 }
1464
1465 Some((window, receiver))
1466 }
1467 }
1468
1469 pub fn make_context_current(&mut self, context: Option<&Window>) {
1474 match context {
1475 Some(window) => unsafe { ffi::glfwMakeContextCurrent(window.ptr) },
1476 None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
1477 }
1478 }
1479
1480 #[cfg(all(target_os = "linux", not(feature = "wayland")))]
1482 pub fn get_x11_display(&self) -> *mut c_void {
1483 unsafe { ffi::glfwGetX11Display() }
1484 }
1485
1486 #[cfg(all(target_os = "linux", feature = "wayland"))]
1488 pub fn get_wayland_display(&self) -> *mut c_void {
1489 unsafe { ffi::glfwGetWaylandDisplay() }
1490 }
1491
1492 pub fn poll_events(&mut self) {
1496 unsafe {
1497 ffi::glfwPollEvents();
1498 }
1499 }
1500
1501 pub fn poll_events_unbuffered<F>(&mut self, mut f: F)
1509 where
1510 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1511 {
1512 let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1513 self.poll_events();
1514 }
1515
1516 pub fn wait_events(&mut self) {
1521 unsafe {
1522 ffi::glfwWaitEvents();
1523 }
1524 }
1525
1526 pub fn wait_events_unbuffered<F>(&mut self, mut f: F)
1531 where
1532 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1533 {
1534 let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1535 self.wait_events();
1536 }
1537
1538 pub fn wait_events_timeout(&mut self, timeout: f64) {
1544 unsafe {
1545 ffi::glfwWaitEventsTimeout(timeout);
1546 }
1547 }
1548
1549 pub fn wait_events_timeout_unbuffered<F>(&mut self, timeout: f64, mut f: F)
1555 where
1556 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1557 {
1558 let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1559 self.wait_events_timeout(timeout);
1560 }
1561
1562 pub fn post_empty_event(&self) {
1568 unsafe {
1569 ffi::glfwPostEmptyEvent();
1570 }
1571 }
1572
1573 pub fn get_time(&self) -> f64 {
1579 unsafe { ffi::glfwGetTime() as f64 }
1580 }
1581
1582 pub fn set_time(&mut self, time: f64) {
1586 unsafe {
1587 ffi::glfwSetTime(time as c_double);
1588 }
1589 }
1590
1591 pub fn get_timer_value(&self) -> u64 {
1593 unsafe { ffi::glfwGetTimerValue() as u64 }
1594 }
1595
1596 pub fn get_timer_frequency(&self) -> u64 {
1598 unsafe { ffi::glfwGetTimerFrequency() as u64 }
1599 }
1600
1601 pub fn set_swap_interval(&mut self, interval: SwapInterval) {
1606 unsafe {
1607 ffi::glfwSwapInterval(match interval {
1608 SwapInterval::None => 0_i32,
1609 SwapInterval::Adaptive => -1_i32,
1610 SwapInterval::Sync(interval) => interval as c_int,
1611 })
1612 }
1613 }
1614
1615 pub fn extension_supported(&self, extension: &str) -> bool {
1620 unsafe {
1621 with_c_str(extension, |extension| {
1622 ffi::glfwExtensionSupported(extension) == ffi::TRUE
1623 })
1624 }
1625 }
1626
1627 #[cfg(feature = "vulkan")]
1636 pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
1637 let mut len: c_uint = 0;
1638
1639 unsafe {
1640 let raw_extensions: *const *const c_char =
1641 ffi::glfwGetRequiredInstanceExtensions(&mut len as *mut c_uint);
1642
1643 if !raw_extensions.is_null() {
1644 return Some(
1645 slice::from_raw_parts(raw_extensions, len as usize)
1646 .iter()
1647 .map(|extensions| string_from_c_str(*extensions))
1648 .collect(),
1649 );
1650 }
1651 }
1652
1653 None
1654 }
1655
1656 pub fn get_proc_address_raw(&self, procname: &str) -> GLProc {
1661 debug_assert!(unsafe { ffi::glfwGetCurrentContext() } != std::ptr::null_mut());
1662 with_c_str(procname, |procname| unsafe {
1663 ffi::glfwGetProcAddress(procname)
1664 })
1665 }
1666
1667 #[cfg(feature = "vulkan")]
1680 pub fn get_instance_proc_address_raw(&self, instance: vk::Instance, procname: &str) -> VkProc {
1681 with_c_str(procname, |procname| unsafe {
1682 ffi::glfwGetInstanceProcAddress(instance, procname)
1683 })
1684 }
1685
1686 #[cfg(feature = "vulkan")]
1691 pub fn get_physical_device_presentation_support_raw(
1692 &self,
1693 instance: vk::Instance,
1694 device: vk::PhysicalDevice,
1695 queue_family: u32,
1696 ) -> bool {
1697 vk::TRUE
1698 == unsafe {
1699 ffi::glfwGetPhysicalDevicePresentationSupport(
1700 instance,
1701 device,
1702 queue_family as c_uint,
1703 ) as u32
1704 }
1705 }
1706
1707 pub fn get_joystick(&self, id: JoystickId) -> Joystick {
1709 Joystick {
1710 id,
1711 glfw: self.clone(),
1712 }
1713 }
1714
1715 pub fn supports_raw_motion(&self) -> bool {
1717 unsafe { ffi::glfwRawMouseMotionSupported() == ffi::TRUE }
1718 }
1719
1720 pub fn update_gamepad_mappings(&self, mappings: &str) -> bool {
1731 unsafe {
1732 with_c_str(mappings, |mappings| {
1733 ffi::glfwUpdateGamepadMappings(mappings) == ffi::TRUE
1734 })
1735 }
1736 }
1737}
1738
1739impl Clone for Glfw {
1740 fn clone(&self) -> Self {
1741 REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
1742 Glfw {
1743 phantom: std::marker::PhantomData,
1744 }
1745 }
1746}
1747
1748impl Drop for Glfw {
1749 fn drop(&mut self) {
1750 let old_diff = REF_COUNT_FOR_GLFW.fetch_sub(1, Ordering::SeqCst);
1751 if old_diff == 1 {
1752 unsafe {
1753 ffi::glfwTerminate();
1754 }
1755 }
1756 }
1757}
1758
1759fn glfw_channel<T>(initial_capacity: usize, max_len: usize) -> (GlfwSender<T>, GlfwReceiver<T>) {
1760 let shared = Arc::new(SharedTransmitter {
1761 queue: Mutex::new(VecDeque::with_capacity(initial_capacity)),
1762 max_len,
1763 });
1764 let (mpsc_sender, mpsc_receiver) = channel();
1765
1766 let sender = GlfwSender {
1767 transmitter: shared.clone(),
1768 sender: mpsc_sender,
1769 };
1770 let receiver = GlfwReceiver {
1771 transmitter: shared.clone(),
1772 receiver: mpsc_receiver,
1773 };
1774 (sender, receiver)
1775}
1776
1777#[derive(Debug)]
1778struct SharedTransmitter<T> {
1779 queue: Mutex<VecDeque<T>>,
1780 max_len: usize,
1781}
1782
1783#[derive(Debug, Clone)]
1784struct GlfwSender<T> {
1785 transmitter: Arc<SharedTransmitter<T>>,
1786 sender: Sender<T>,
1787}
1788
1789impl<T> GlfwSender<T> {
1790 fn send(&self, v: T) {
1791 let mut queue = self.transmitter.queue.lock().unwrap();
1792 if queue.len() >= self.transmitter.max_len {
1793 let _ = self.sender.send(v);
1794 } else {
1795 queue.push_back(v);
1796 }
1797 }
1798}
1799
1800#[derive(Debug)]
1801pub struct GlfwReceiver<T> {
1802 transmitter: Arc<SharedTransmitter<T>>,
1803 receiver: Receiver<T>,
1804}
1805
1806impl<T> GlfwReceiver<T> {
1807 pub fn receive(&self) -> Option<T> {
1808 let ret = self.transmitter.queue.lock().unwrap().pop_front();
1809 if ret.is_some() {
1810 ret
1811 } else {
1812 match self.receiver.try_recv() {
1813 Ok(ret) => Some(ret),
1814 Err(_) => None,
1815 }
1816 }
1817 }
1818}
1819
1820struct WindowCallbacks {
1821 window_ptr: *mut Window,
1822 sender: GlfwSender<(f64, WindowEvent)>,
1823 pos_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1824 size_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1825 close_callback: Option<Box<dyn FnMut(&mut Window)>>,
1826 refresh_callback: Option<Box<dyn FnMut(&mut Window)>>,
1827 focus_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1828 iconify_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1829 framebuffer_size_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1830 key_callback: Option<Box<dyn FnMut(&mut Window, Key, Scancode, Action, Modifiers)>>,
1831 char_callback: Option<Box<dyn FnMut(&mut Window, char)>>,
1832 char_mods_callback: Option<Box<dyn FnMut(&mut Window, char, Modifiers)>>,
1833 mouse_button_callback: Option<Box<dyn FnMut(&mut Window, MouseButton, Action, Modifiers)>>,
1834 cursor_pos_callback: Option<Box<dyn FnMut(&mut Window, f64, f64)>>,
1835 cursor_enter_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1836 scroll_callback: Option<Box<dyn FnMut(&mut Window, f64, f64)>>,
1837 drag_and_drop_callback: Option<Box<dyn FnMut(&mut Window, Vec<PathBuf>)>>,
1838 maximize_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1839 content_scale_callback: Option<Box<dyn FnMut(&mut Window, f32, f32)>>,
1840 pos_polling: bool,
1841 size_polling: bool,
1842 close_polling: bool,
1843 refresh_polling: bool,
1844 focus_polling: bool,
1845 iconify_polling: bool,
1846 framebuffer_size_polling: bool,
1847 key_polling: bool,
1848 char_polling: bool,
1849 char_mods_polling: bool,
1850 mouse_button_polling: bool,
1851 cursor_pos_polling: bool,
1852 cursor_enter_polling: bool,
1853 scroll_polling: bool,
1854 drag_and_drop_polling: bool,
1855 maximize_polling: bool,
1856 content_scale_polling: bool,
1857}
1858
1859impl WindowCallbacks {
1860 fn new(sender: GlfwSender<(f64, WindowEvent)>) -> Self {
1861 Self {
1862 window_ptr: std::ptr::null_mut(),
1863 sender,
1864 pos_callback: None,
1865 size_callback: None,
1866 close_callback: None,
1867 refresh_callback: None,
1868 focus_callback: None,
1869 iconify_callback: None,
1870 framebuffer_size_callback: None,
1871 key_callback: None,
1872 char_callback: None,
1873 char_mods_callback: None,
1874 mouse_button_callback: None,
1875 cursor_pos_callback: None,
1876 cursor_enter_callback: None,
1877 scroll_callback: None,
1878 drag_and_drop_callback: None,
1879 maximize_callback: None,
1880 content_scale_callback: None,
1881 pos_polling: false,
1882 size_polling: false,
1883 close_polling: false,
1884 refresh_polling: false,
1885 focus_polling: false,
1886 iconify_polling: false,
1887 framebuffer_size_polling: false,
1888 key_polling: false,
1889 char_polling: false,
1890 char_mods_polling: false,
1891 mouse_button_polling: false,
1892 cursor_pos_polling: false,
1893 cursor_enter_polling: false,
1894 scroll_polling: false,
1895 drag_and_drop_polling: false,
1896 maximize_polling: false,
1897 content_scale_polling: false,
1898 }
1899 }
1900
1901 fn get_callbacks<'a>(window: *mut GLFWwindow) -> &'a mut WindowCallbacks {
1902 unsafe { &mut *(ffi::glfwGetWindowUserPointer(window) as *mut WindowCallbacks) }
1903 }
1904}
1905
1906pub fn get_error() -> Error {
1908 unsafe { mem::transmute(ffi::glfwGetError(null_mut())) }
1909}
1910
1911pub fn get_error_string() -> (Error, String) {
1913 unsafe {
1914 let mut description: *const c_char = null();
1915 let error: Error = mem::transmute(ffi::glfwGetError(&mut description));
1916 (error, string_from_c_str(description))
1917 }
1918}
1919
1920pub fn get_version() -> Version {
1922 unsafe {
1923 let mut major = 0;
1924 let mut minor = 0;
1925 let mut patch = 0;
1926 ffi::glfwGetVersion(&mut major, &mut minor, &mut patch);
1927 Version {
1928 major: major as u64,
1929 minor: minor as u64,
1930 patch: patch as u64,
1931 }
1932 }
1933}
1934
1935pub unsafe fn string_from_c_str(c_str: *const c_char) -> String {
1937 String::from_utf8_lossy(CStr::from_ptr(c_str).to_bytes()).into_owned()
1938}
1939
1940pub unsafe fn string_from_nullable_c_str(c_str: *const c_char) -> Option<String> {
1942 if c_str.is_null() {
1943 None
1944 } else {
1945 Some(string_from_c_str(c_str))
1946 }
1947}
1948
1949pub fn with_c_str<F, T>(s: &str, f: F) -> T
1951where
1952 F: FnOnce(*const c_char) -> T,
1953{
1954 let c_str = CString::new(s.as_bytes());
1955 f(c_str.unwrap().as_bytes_with_nul().as_ptr() as *const _)
1956}
1957
1958pub fn get_version_string() -> String {
1960 unsafe { string_from_c_str(ffi::glfwGetVersionString()) }
1961}
1962
1963#[allow(missing_copy_implementations)]
1965pub struct Monitor {
1966 ptr: *mut ffi::GLFWmonitor,
1967}
1968
1969impl std::fmt::Debug for Monitor {
1970 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1971 write!(f, "Monitor({:p})", self.ptr)
1972 }
1973}
1974
1975impl Monitor {
1976 pub fn get_pos(&self) -> (i32, i32) {
1978 unsafe {
1979 let mut xpos = 0;
1980 let mut ypos = 0;
1981 ffi::glfwGetMonitorPos(self.ptr, &mut xpos, &mut ypos);
1982 (xpos as i32, ypos as i32)
1983 }
1984 }
1985
1986 pub fn get_physical_size(&self) -> (i32, i32) {
1988 unsafe {
1989 let mut width = 0;
1990 let mut height = 0;
1991 ffi::glfwGetMonitorPhysicalSize(self.ptr, &mut width, &mut height);
1992 (width as i32, height as i32)
1993 }
1994 }
1995
1996 pub fn get_name(&self) -> Option<String> {
1998 unsafe { string_from_nullable_c_str(ffi::glfwGetMonitorName(self.ptr)) }
1999 }
2000
2001 pub fn get_video_modes(&self) -> Vec<VidMode> {
2003 unsafe {
2004 let mut count = 0;
2005 let ptr = ffi::glfwGetVideoModes(self.ptr, &mut count);
2006 slice::from_raw_parts(ptr, count as usize)
2007 .iter()
2008 .map(VidMode::from_glfw_vid_mode)
2009 .collect()
2010 }
2011 }
2012
2013 pub fn get_video_mode(&self) -> Option<VidMode> {
2015 unsafe {
2016 let ptr = ffi::glfwGetVideoMode(self.ptr);
2019 if ptr.is_null() {
2020 None
2021 } else {
2022 Some(VidMode::from_glfw_vid_mode(&*ptr))
2023 }
2024 }
2025 }
2026
2027 pub fn set_gamma(&mut self, gamma: f32) {
2029 unsafe {
2030 ffi::glfwSetGamma(self.ptr, gamma as c_float);
2031 }
2032 }
2033
2034 pub fn get_gamma_ramp(&self) -> GammaRamp {
2036 unsafe {
2037 let llramp = *ffi::glfwGetGammaRamp(self.ptr);
2038 GammaRamp {
2039 red: slice::from_raw_parts(llramp.red as *const c_ushort, llramp.size as usize)
2040 .iter()
2041 .copied()
2042 .collect(),
2043 green: slice::from_raw_parts(llramp.green as *const c_ushort, llramp.size as usize)
2044 .iter()
2045 .copied()
2046 .collect(),
2047 blue: slice::from_raw_parts(llramp.blue as *const c_ushort, llramp.size as usize)
2048 .iter()
2049 .copied()
2050 .collect(),
2051 }
2052 }
2053 }
2054
2055 pub fn set_gamma_ramp(&mut self, ramp: &mut GammaRamp) {
2057 unsafe {
2058 ffi::glfwSetGammaRamp(
2059 self.ptr,
2060 &ffi::GLFWgammaramp {
2061 red: ramp.red.as_mut_ptr(),
2062 green: ramp.green.as_mut_ptr(),
2063 blue: ramp.blue.as_mut_ptr(),
2064 size: ramp.red.len() as u32,
2065 },
2066 );
2067 }
2068 }
2069
2070 pub fn get_content_scale(&self) -> (f32, f32) {
2072 unsafe {
2073 let mut xscale = 0.0_f32;
2074 let mut yscale = 0.0_f32;
2075 ffi::glfwGetMonitorContentScale(self.ptr, &mut xscale, &mut yscale);
2076 (xscale, yscale)
2077 }
2078 }
2079
2080 pub fn get_workarea(&self) -> (i32, i32, i32, i32) {
2082 unsafe {
2083 let mut xpos = 0;
2084 let mut ypos = 0;
2085 let mut width = 0;
2086 let mut height = 0;
2087 ffi::glfwGetMonitorWorkarea(self.ptr, &mut xpos, &mut ypos, &mut width, &mut height);
2088 (xpos, ypos, width, height)
2089 }
2090 }
2091}
2092
2093#[repr(i32)]
2095#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2096#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2097pub enum MonitorEvent {
2098 Connected = ffi::CONNECTED,
2099 Disconnected = ffi::DISCONNECTED,
2100}
2101
2102impl VidMode {
2103 fn from_glfw_vid_mode(mode: &ffi::GLFWvidmode) -> VidMode {
2104 VidMode {
2105 width: mode.width as u32,
2106 height: mode.height as u32,
2107 red_bits: mode.redBits as u32,
2108 green_bits: mode.greenBits as u32,
2109 blue_bits: mode.blueBits as u32,
2110 refresh_rate: mode.refreshRate as u32,
2111 }
2112 }
2113}
2114
2115impl fmt::Debug for VidMode {
2116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2126 write!(
2127 f,
2128 "{} x {}, {} = {} + {} + {}, {} Hz",
2129 self.width,
2130 self.height,
2131 self.red_bits + self.green_bits + self.blue_bits,
2132 self.red_bits,
2133 self.green_bits,
2134 self.blue_bits,
2135 self.refresh_rate
2136 )
2137 }
2138}
2139
2140#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2142#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2143pub enum WindowHint {
2144 RedBits(Option<u32>),
2146 GreenBits(Option<u32>),
2148 BlueBits(Option<u32>),
2150 AlphaBits(Option<u32>),
2152 DepthBits(Option<u32>),
2154 StencilBits(Option<u32>),
2156 AccumRedBits(Option<u32>),
2158 AccumGreenBits(Option<u32>),
2160 AccumBlueBits(Option<u32>),
2162 AccumAlphaBits(Option<u32>),
2164 AuxBuffers(Option<u32>),
2166 Stereo(bool),
2168 Samples(Option<u32>),
2171 SRgbCapable(bool),
2173 RefreshRate(Option<u32>),
2178 ClientApi(ClientApiHint),
2180 ContextVersionMajor(u32),
2186 ContextVersionMinor(u32),
2192 ContextVersion(u32, u32),
2202 ContextRobustness(ContextRobustnessHint),
2204 OpenGlForwardCompat(bool),
2211 OpenGlDebugContext(bool),
2216 OpenGlProfile(OpenGlProfileHint),
2221 Resizable(bool),
2227 Visible(bool),
2231 Decorated(bool),
2236 AutoIconify(bool),
2241 Floating(bool),
2246 Focused(bool),
2250 Maximized(bool),
2254 ContextNoError(bool),
2257 ContextCreationApi(ContextCreationApi),
2259 ContextReleaseBehavior(ContextReleaseBehavior),
2261 DoubleBuffer(bool),
2268 CenterCursor(bool),
2272 TransparentFramebuffer(bool),
2277 FocusOnShow(bool),
2279 ScaleToMonitor(bool),
2284 CocoaRetinaFramebuffer(bool),
2288 CocoaFrameName(Option<String>),
2293 CocoaGraphicsSwitching(bool),
2307 X11ClassName(Option<String>),
2309 X11InstanceName(Option<String>),
2311}
2312
2313#[repr(i32)]
2315#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2317pub enum ClientApiHint {
2318 NoApi = ffi::NO_API,
2319 OpenGl = ffi::OPENGL_API,
2320 OpenGlEs = ffi::OPENGL_ES_API,
2321}
2322
2323#[repr(i32)]
2325#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2326#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2327pub enum ContextRobustnessHint {
2328 NoRobustness = ffi::NO_ROBUSTNESS,
2329 NoResetNotification = ffi::NO_RESET_NOTIFICATION,
2330 LoseContextOnReset = ffi::LOSE_CONTEXT_ON_RESET,
2331}
2332
2333#[repr(i32)]
2335#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2336#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2337pub enum OpenGlProfileHint {
2338 Any = ffi::OPENGL_ANY_PROFILE,
2339 Core = ffi::OPENGL_CORE_PROFILE,
2340 Compat = ffi::OPENGL_COMPAT_PROFILE,
2341}
2342
2343#[derive(Copy, Clone, Debug)]
2345pub enum WindowMode<'a> {
2346 FullScreen(&'a Monitor),
2348
2349 Windowed,
2351}
2352
2353impl<'a> WindowMode<'a> {
2355 fn to_ptr(&self) -> *mut ffi::GLFWmonitor {
2358 match *self {
2359 WindowMode::FullScreen(monitor) => monitor.ptr,
2360 WindowMode::Windowed => ptr::null_mut(),
2361 }
2362 }
2363}
2364
2365bitflags! {
2366 #[doc = "Key modifiers (e.g., Shift, Control, Alt, Super)"]
2367 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2368 pub struct Modifiers: ::std::os::raw::c_int {
2369 const Shift = crate::ffi::MOD_SHIFT;
2370 const Control = crate::ffi::MOD_CONTROL;
2371 const Alt = crate::ffi::MOD_ALT;
2372 const Super = crate::ffi::MOD_SUPER;
2373 const CapsLock = crate::ffi::MOD_CAPS_LOCK;
2374 const NumLock = crate::ffi::MOD_NUM_LOCK;
2375 }
2376}
2377
2378pub type Scancode = c_int;
2380
2381#[derive(Clone, PartialEq, PartialOrd, Debug)]
2383#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2384pub enum WindowEvent {
2385 Pos(i32, i32),
2386 Size(i32, i32),
2387 Close,
2388 Refresh,
2389 Focus(bool),
2390 Iconify(bool),
2391 FramebufferSize(i32, i32),
2392 MouseButton(MouseButton, Action, Modifiers),
2393 CursorPos(f64, f64),
2394 CursorEnter(bool),
2395 Scroll(f64, f64),
2396 Key(Key, Scancode, Action, Modifiers),
2397 Char(char),
2398 CharModifiers(char, Modifiers),
2399 FileDrop(Vec<PathBuf>),
2400 Maximize(bool),
2401 ContentScale(f32, f32),
2402}
2403
2404pub fn flush_messages<Message: Send>(
2416 receiver: &GlfwReceiver<Message>,
2417) -> FlushedMessages<'_, Message> {
2418 FlushedMessages(receiver)
2419}
2420
2421#[derive(Debug)]
2424pub struct FlushedMessages<'a, Message: Send>(&'a GlfwReceiver<Message>);
2425
2426unsafe impl<'a, Message: 'a + Send> Send for FlushedMessages<'a, Message> {}
2427
2428impl<'a, Message: 'static + Send> Iterator for FlushedMessages<'a, Message> {
2429 type Item = Message;
2430
2431 fn next(&mut self) -> Option<Message> {
2432 let FlushedMessages(receiver) = *self;
2433 receiver.receive()
2434 }
2435}
2436
2437#[derive(Debug)]
2439pub struct Window {
2440 ptr: *mut ffi::GLFWwindow,
2441 pub is_shared: bool,
2442 drop_sender: Option<Sender<()>>,
2444 #[allow(unused)]
2448 drop_receiver: Receiver<()>,
2449 current_cursor: Option<Cursor>,
2452 pub glfw: Glfw,
2453}
2454
2455impl Window {
2456 pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
2462 if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
2463 self.make_current();
2464 }
2465
2466 self.glfw.get_proc_address_raw(procname)
2467 }
2468
2469 #[cfg(feature = "vulkan")]
2482 pub fn get_instance_proc_address(&mut self, instance: vk::Instance, procname: &str) -> VkProc {
2483 self.glfw.get_instance_proc_address_raw(instance, procname)
2484 }
2485
2486 #[cfg(feature = "vulkan")]
2491 pub fn get_physical_device_presentation_support(
2492 &self,
2493 instance: vk::Instance,
2494 device: vk::PhysicalDevice,
2495 queue_family: u32,
2496 ) -> bool {
2497 self.glfw
2498 .get_physical_device_presentation_support_raw(instance, device, queue_family)
2499 }
2500
2501 #[cfg(feature = "vulkan")]
2503 pub fn create_window_surface(
2504 &self,
2505 instance: vk::Instance,
2506 allocator: *const vk::AllocationCallbacks<'_>,
2507 surface: *mut vk::SurfaceKHR,
2508 ) -> vk::Result {
2509 unsafe { ffi::glfwCreateWindowSurface(instance, self.ptr, allocator, surface) }
2510 }
2511
2512 pub fn create_shared(
2516 &self,
2517 width: u32,
2518 height: u32,
2519 title: &str,
2520 mode: WindowMode<'_>,
2521 ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
2522 self.glfw
2523 .create_window_intern(width, height, title, mode, Some(self))
2524 }
2525
2526 pub fn close(self) {}
2529
2530 pub fn render_context(&mut self) -> PRenderContext {
2533 PRenderContext(Box::new(RenderContext {
2534 ptr: self.ptr,
2535 glfw: self.glfw.clone(),
2536 drop_sender: self.drop_sender.as_ref().unwrap().clone(),
2538 }))
2539 }
2540
2541 pub fn should_close(&self) -> bool {
2543 unsafe { ffi::glfwWindowShouldClose(self.ptr) == ffi::TRUE }
2544 }
2545
2546 pub fn set_should_close(&mut self, value: bool) {
2548 unsafe { ffi::glfwSetWindowShouldClose(self.ptr, value as c_int) }
2549 }
2550
2551 pub fn set_title(&mut self, title: &str) {
2555 unsafe {
2556 with_c_str(title, |title| {
2557 ffi::glfwSetWindowTitle(self.ptr, title);
2558 });
2559 }
2560 }
2561
2562 pub fn get_pos(&self) -> (i32, i32) {
2564 unsafe {
2565 let mut xpos = 0;
2566 let mut ypos = 0;
2567 ffi::glfwGetWindowPos(self.ptr, &mut xpos, &mut ypos);
2568 (xpos as i32, ypos as i32)
2569 }
2570 }
2571
2572 pub fn set_pos(&mut self, xpos: i32, ypos: i32) {
2574 unsafe {
2575 ffi::glfwSetWindowPos(self.ptr, xpos as c_int, ypos as c_int);
2576 }
2577 }
2578
2579 pub fn get_size(&self) -> (i32, i32) {
2581 unsafe {
2582 let mut width = 0;
2583 let mut height = 0;
2584 ffi::glfwGetWindowSize(self.ptr, &mut width, &mut height);
2585 (width as i32, height as i32)
2586 }
2587 }
2588
2589 pub fn set_size(&mut self, width: i32, height: i32) {
2591 unsafe {
2592 ffi::glfwSetWindowSize(self.ptr, width as c_int, height as c_int);
2593 }
2594 }
2595
2596 pub fn get_frame_size(&self) -> (i32, i32, i32, i32) {
2600 let (mut left, mut top, mut right, mut bottom): (i32, i32, i32, i32) = (0, 0, 0, 0);
2601
2602 unsafe {
2603 ffi::glfwGetWindowFrameSize(
2604 self.ptr,
2605 &mut left as *mut c_int,
2606 &mut top as *mut c_int,
2607 &mut right as *mut c_int,
2608 &mut bottom as *mut c_int,
2609 );
2610 }
2611
2612 (left, top, right, bottom)
2613 }
2614
2615 pub fn get_framebuffer_size(&self) -> (i32, i32) {
2617 unsafe {
2618 let mut width = 0;
2619 let mut height = 0;
2620 ffi::glfwGetFramebufferSize(self.ptr, &mut width, &mut height);
2621 (width as i32, height as i32)
2622 }
2623 }
2624
2625 pub fn set_aspect_ratio(&mut self, numer: u32, denum: u32) {
2627 unsafe { ffi::glfwSetWindowAspectRatio(self.ptr, numer as c_int, denum as c_int) }
2628 }
2629
2630 pub fn set_size_limits(
2636 &mut self,
2637 minwidth: Option<u32>,
2638 minheight: Option<u32>,
2639 maxwidth: Option<u32>,
2640 maxheight: Option<u32>,
2641 ) {
2642 unsafe {
2643 ffi::glfwSetWindowSizeLimits(
2644 self.ptr,
2645 unwrap_dont_care(minwidth),
2646 unwrap_dont_care(minheight),
2647 unwrap_dont_care(maxwidth),
2648 unwrap_dont_care(maxheight),
2649 )
2650 }
2651 }
2652
2653 pub fn iconify(&mut self) {
2655 unsafe {
2656 ffi::glfwIconifyWindow(self.ptr);
2657 }
2658 }
2659
2660 pub fn restore(&mut self) {
2662 unsafe {
2663 ffi::glfwRestoreWindow(self.ptr);
2664 }
2665 }
2666
2667 pub fn maximize(&mut self) {
2669 unsafe { ffi::glfwMaximizeWindow(self.ptr) }
2670 }
2671
2672 pub fn show(&mut self) {
2674 unsafe {
2675 ffi::glfwShowWindow(self.ptr);
2676 }
2677 }
2678
2679 pub fn hide(&mut self) {
2681 unsafe {
2682 ffi::glfwHideWindow(self.ptr);
2683 }
2684 }
2685
2686 pub fn with_window_mode<T, F>(&self, f: F) -> T
2699 where
2700 F: FnOnce(WindowMode<'_>) -> T,
2701 {
2702 let ptr = unsafe { ffi::glfwGetWindowMonitor(self.ptr) };
2703 if ptr.is_null() {
2704 f(WindowMode::Windowed)
2705 } else {
2706 f(WindowMode::FullScreen(&Monitor { ptr }))
2707 }
2708 }
2709
2710 pub fn set_monitor(
2712 &mut self,
2713 mode: WindowMode<'_>,
2714 xpos: i32,
2715 ypos: i32,
2716 width: u32,
2717 height: u32,
2718 refresh_rate: Option<u32>,
2719 ) {
2720 let monitor_ptr = if let WindowMode::FullScreen(monitor) = mode {
2721 monitor.ptr
2722 } else {
2723 ptr::null_mut()
2724 };
2725
2726 unsafe {
2727 ffi::glfwSetWindowMonitor(
2728 self.ptr,
2729 monitor_ptr,
2730 xpos as c_int,
2731 ypos as c_int,
2732 width as c_int,
2733 height as c_int,
2734 unwrap_dont_care(refresh_rate),
2735 )
2736 }
2737 }
2738
2739 pub fn focus(&mut self) {
2744 unsafe { ffi::glfwFocusWindow(self.ptr) }
2745 }
2746
2747 pub fn is_focused(&self) -> bool {
2749 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FOCUSED) == ffi::TRUE }
2750 }
2751
2752 pub fn is_iconified(&self) -> bool {
2754 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::ICONIFIED) == ffi::TRUE }
2755 }
2756
2757 pub fn is_maximized(&self) -> bool {
2759 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::MAXIMIZED) == ffi::TRUE }
2760 }
2761
2762 pub fn get_client_api(&self) -> c_int {
2764 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::CLIENT_API) }
2765 }
2766
2767 pub fn get_context_version(&self) -> Version {
2774 unsafe {
2775 Version {
2776 major: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_VERSION_MAJOR) as u64,
2777 minor: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_VERSION_MINOR) as u64,
2778 patch: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_REVISION) as u64,
2779 }
2780 }
2781 }
2782
2783 pub fn get_context_robustness(&self) -> c_int {
2785 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_ROBUSTNESS) }
2786 }
2787
2788 pub fn is_opengl_forward_compat(&self) -> bool {
2790 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_FORWARD_COMPAT) == ffi::TRUE }
2791 }
2792
2793 pub fn is_opengl_debug_context(&self) -> bool {
2795 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_DEBUG_CONTEXT) == ffi::TRUE }
2796 }
2797
2798 pub fn get_opengl_profile(&self) -> c_int {
2800 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_PROFILE) }
2801 }
2802
2803 pub fn is_resizable(&self) -> bool {
2805 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::RESIZABLE) == ffi::TRUE }
2806 }
2807
2808 pub fn set_resizable(&mut self, resizable: bool) {
2810 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::RESIZABLE, resizable as c_int) }
2811 }
2812
2813 pub fn is_visible(&self) -> bool {
2815 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::VISIBLE) == ffi::TRUE }
2816 }
2817
2818 pub fn is_decorated(&self) -> bool {
2820 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::DECORATED) == ffi::TRUE }
2821 }
2822
2823 pub fn set_decorated(&mut self, decorated: bool) {
2825 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::DECORATED, decorated as c_int) }
2826 }
2827
2828 pub fn is_auto_iconify(&self) -> bool {
2830 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::AUTO_ICONIFY) == ffi::TRUE }
2831 }
2832
2833 pub fn set_auto_iconify(&mut self, auto_iconify: bool) {
2835 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::AUTO_ICONIFY, auto_iconify as c_int) }
2836 }
2837
2838 pub fn is_floating(&self) -> bool {
2840 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FLOATING) == ffi::TRUE }
2841 }
2842
2843 pub fn set_floating(&mut self, floating: bool) {
2845 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::FLOATING, floating as c_int) }
2846 }
2847
2848 pub fn is_framebuffer_transparent(&self) -> bool {
2850 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::TRANSPARENT_FRAMEBUFFER) == ffi::TRUE }
2851 }
2852
2853 pub fn is_focus_on_show(&self) -> bool {
2855 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FOCUS_ON_SHOW) == ffi::TRUE }
2856 }
2857
2858 pub fn set_focus_on_show(&mut self, focus_on_show: bool) {
2860 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::FOCUS_ON_SHOW, focus_on_show as c_int) }
2861 }
2862
2863 pub fn is_hovered(&self) -> bool {
2865 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::HOVERED) == ffi::TRUE }
2866 }
2867
2868 new_callback!(
2869 doc -> "Wrapper for `glfwSetWindowPosCallback`.",
2870 set -> set_pos_callback,
2871 unset -> unset_pos_callback,
2872 poll -> set_pos_polling,
2873 callback_field -> pos_callback,
2874 poll_field -> pos_polling,
2875 window_event -> Pos(i32, i32),
2876 glfw -> glfwSetWindowPosCallback(x: c_int, y: c_int),
2877 convert_args -> (x as i32, y as i32),
2878 secret -> _pos_callback
2879 );
2880
2881 new_callback!(
2882 doc -> "Wrapper for `glfwSetWindowSizeCallback`.",
2883 set -> set_size_callback,
2884 unset -> unset_size_callback,
2885 poll -> set_size_polling,
2886 callback_field -> size_callback,
2887 poll_field -> size_polling,
2888 window_event -> Size(i32, i32),
2889 glfw -> glfwSetWindowSizeCallback(width: c_int, height: c_int),
2890 convert_args -> (width as i32, height as i32),
2891 secret -> _size_callback
2892 );
2893
2894 new_callback!(
2895 doc -> "Wrapper for `glfwSetWindowCloseCallback`.",
2896 set -> set_close_callback,
2897 unset -> unset_close_callback,
2898 poll -> set_close_polling,
2899 callback_field -> close_callback,
2900 poll_field -> close_polling,
2901 window_event -> Close,
2902 glfw -> glfwSetWindowCloseCallback(),
2903 convert_args -> (),
2904 secret -> _close_callback
2905 );
2906
2907 new_callback!(
2908 doc -> "Wrapper for `glfwSetWindowRefreshCallback`.",
2909 set -> set_refresh_callback,
2910 unset -> unset_refresh_callback,
2911 poll -> set_refresh_polling,
2912 callback_field -> refresh_callback,
2913 poll_field -> refresh_polling,
2914 window_event -> Refresh,
2915 glfw -> glfwSetWindowRefreshCallback(),
2916 convert_args -> (),
2917 secret -> _refresh_callback
2918 );
2919
2920 new_callback!(
2921 doc -> "Wrapper for `glfwSetWindowFocusCallback`.",
2922 set -> set_focus_callback,
2923 unset -> unset_focus_callback,
2924 poll -> set_focus_polling,
2925 callback_field -> focus_callback,
2926 poll_field -> focus_polling,
2927 window_event -> Focus(bool),
2928 glfw -> glfwSetWindowFocusCallback(focused: c_int),
2929 convert_args -> (focused == ffi::TRUE),
2930 secret -> _focus_callback
2931 );
2932
2933 new_callback!(
2934 doc -> "Wrapper for `glfwSetWindowIconifyCallback`.",
2935 set -> set_iconify_callback,
2936 unset -> unset_iconify_callback,
2937 poll -> set_iconify_polling,
2938 callback_field -> iconify_callback,
2939 poll_field -> iconify_polling,
2940 window_event -> Iconify(bool),
2941 glfw -> glfwSetWindowIconifyCallback(iconified: c_int),
2942 convert_args -> (iconified == ffi::TRUE),
2943 secret -> _iconify_callback
2944 );
2945
2946 new_callback!(
2947 doc -> "Wrapper for `glfwSetFramebufferSizeCallback`.",
2948 set -> set_framebuffer_size_callback,
2949 unset -> unset_framebuffer_size_callback,
2950 poll -> set_framebuffer_size_polling,
2951 callback_field -> framebuffer_size_callback,
2952 poll_field -> framebuffer_size_polling,
2953 window_event -> FramebufferSize(i32, i32),
2954 glfw -> glfwSetFramebufferSizeCallback(width: c_int, height: c_int),
2955 convert_args -> (width as i32, height as i32),
2956 secret -> _framebuffer_size_callback
2957 );
2958
2959 new_callback!(
2960 doc -> "Wrapper for `glfwSetKeyCallback`.",
2961 set -> set_key_callback,
2962 unset -> unset_key_callback,
2963 poll -> set_key_polling,
2964 callback_field -> key_callback,
2965 poll_field -> key_polling,
2966 window_event -> Key(Key, Scancode, Action, Modifiers),
2967 glfw -> glfwSetKeyCallback(key: c_int, scancode: c_int, action: c_int, mods: c_int),
2968 convert_args -> (
2969 mem::transmute(key),
2970 scancode, mem::transmute(action),
2971 Modifiers::from_bits(mods).unwrap()
2972 ),
2973 secret -> _key_callback
2974 );
2975
2976 new_callback!(
2977 doc -> "Wrapper for `glfwSetCharCallback`.",
2978 set -> set_char_callback,
2979 unset -> unset_char_callback,
2980 poll -> set_char_polling,
2981 callback_field -> char_callback,
2982 poll_field -> char_polling,
2983 window_event -> Char(char),
2984 glfw -> glfwSetCharCallback(character: c_uint),
2985 convert_args -> (::std::char::from_u32(character).unwrap()),
2986 secret -> _char_callback
2987 );
2988
2989 new_callback!(
2990 doc -> "Wrapper for `glfwSetCharModsCallback`.",
2991 set -> set_char_mods_callback,
2992 unset -> unset_char_mods_callback,
2993 poll -> set_char_mods_polling,
2994 callback_field -> char_mods_callback,
2995 poll_field -> char_mods_polling,
2996 window_event -> CharModifiers(char, Modifiers),
2997 glfw -> glfwSetCharModsCallback(character: c_uint, mods: c_int),
2998 convert_args -> (
2999 ::std::char::from_u32(character).unwrap(),
3000 Modifiers::from_bits(mods).unwrap()
3001 ),
3002 secret -> _char_mods_callback
3003 );
3004
3005 new_callback!(
3006 doc -> "Wrapper for `glfwSetMouseButtonCallback`.",
3007 set -> set_mouse_button_callback,
3008 unset -> unset_mouse_button_callback,
3009 poll -> set_mouse_button_polling,
3010 callback_field -> mouse_button_callback,
3011 poll_field -> mouse_button_polling,
3012 window_event -> MouseButton(MouseButton, Action, Modifiers),
3013 glfw -> glfwSetMouseButtonCallback(button: c_int, action: c_int, mods: c_int),
3014 convert_args -> (
3015 mem::transmute(button),
3016 mem::transmute(action),
3017 Modifiers::from_bits(mods).unwrap()
3018 ),
3019 secret -> _mouse_button_callback
3020 );
3021
3022 new_callback!(
3023 doc -> "Wrapper for `glfwSetCursorPosCallback`.",
3024 set -> set_cursor_pos_callback,
3025 unset -> unset_cursor_pos_callback,
3026 poll -> set_cursor_pos_polling,
3027 callback_field -> cursor_pos_callback,
3028 poll_field -> cursor_pos_polling,
3029 window_event -> CursorPos(f64, f64),
3030 glfw -> glfwSetCursorPosCallback(x: c_double, y: c_double),
3031 convert_args -> (x as f64, y as f64),
3032 secret -> _cursor_pos_callback
3033 );
3034
3035 new_callback!(
3036 doc -> "Wrapper for `glfwSetCursorEnterCallback`.",
3037 set -> set_cursor_enter_callback,
3038 unset -> unset_cursor_enter_callback,
3039 poll -> set_cursor_enter_polling,
3040 callback_field -> cursor_enter_callback,
3041 poll_field -> cursor_enter_polling,
3042 window_event -> CursorEnter(bool),
3043 glfw -> glfwSetCursorEnterCallback(entered: c_int),
3044 convert_args -> (entered == ffi::TRUE),
3045 secret -> _cursor_enter_callback
3046 );
3047
3048 new_callback!(
3049 doc -> "Wrapper for `glfwSetScrollCallback`.",
3050 set -> set_scroll_callback,
3051 unset -> unset_scroll_callback,
3052 poll -> set_scroll_polling,
3053 callback_field -> scroll_callback,
3054 poll_field -> scroll_polling,
3055 window_event -> Scroll(f64, f64),
3056 glfw -> glfwSetScrollCallback(x: c_double, y: c_double),
3057 convert_args -> (x as f64, y as f64),
3058 secret -> _scroll_callback
3059 );
3060
3061 new_callback!(
3062 doc -> "Wrapper for `glfwSetDropCallback`.",
3063 set -> set_drag_and_drop_callback,
3064 unset -> unset_drag_and_drop_callback,
3065 poll -> set_drag_and_drop_polling,
3066 callback_field -> drag_and_drop_callback,
3067 poll_field -> drag_and_drop_polling,
3068 window_event -> FileDrop(Vec<PathBuf>),
3069 glfw -> glfwSetDropCallback(num_paths: c_int, paths: *mut *const c_char),
3070 convert_args -> ({
3071 slice::from_raw_parts(paths, num_paths as usize)
3072 .iter()
3073 .map(|path| PathBuf::from(std::str::from_utf8({
3074 CStr::from_ptr(*path)
3075 .to_bytes()
3076 })
3077 .unwrap()
3078 .to_string()))
3079 .collect()
3080 }),
3081 secret -> _drag_and_drop_callback
3082 );
3083
3084 new_callback!(
3085 doc -> "Wrapper for `glfwSetWindowMaximizeCallback`.",
3086 set -> set_maximize_callback,
3087 unset -> unset_maximize_callback,
3088 poll -> set_maximize_polling,
3089 callback_field -> maximize_callback,
3090 poll_field -> maximize_polling,
3091 window_event -> Maximize(bool),
3092 glfw -> glfwSetWindowMaximizeCallback(maximized: c_int),
3093 convert_args -> (maximized == ffi::TRUE),
3094 secret -> _maximize_callback
3095 );
3096
3097 new_callback!(
3098 doc -> "Wrapper for `glfwSetWindowContentScaleCallback`.",
3099 set -> set_content_scale_callback,
3100 unset -> unset_content_scale_callback,
3101 poll -> set_content_scale_polling,
3102 callback_field -> content_scale_callback,
3103 poll_field -> content_scale_polling,
3104 window_event -> ContentScale(f32, f32),
3105 glfw -> glfwSetWindowContentScaleCallback(xscale: c_float, yscale: c_float),
3106 convert_args -> (xscale as f32, yscale as f32),
3107 secret -> _content_scale_callback
3108 );
3109
3110 pub fn set_all_polling(&mut self, should_poll: bool) {
3112 self.set_pos_polling(should_poll);
3113 self.set_size_polling(should_poll);
3114 self.set_close_polling(should_poll);
3115 self.set_refresh_polling(should_poll);
3116 self.set_focus_polling(should_poll);
3117 self.set_iconify_polling(should_poll);
3118 self.set_framebuffer_size_polling(should_poll);
3119 self.set_key_polling(should_poll);
3120 self.set_char_polling(should_poll);
3121 self.set_char_mods_polling(should_poll);
3122 self.set_mouse_button_polling(should_poll);
3123 self.set_cursor_pos_polling(should_poll);
3124 self.set_cursor_enter_polling(should_poll);
3125 self.set_scroll_polling(should_poll);
3126 self.set_drag_and_drop_polling(should_poll);
3127 self.set_maximize_polling(should_poll);
3128 self.set_content_scale_polling(should_poll);
3129 }
3130
3131 pub fn get_cursor_mode(&self) -> CursorMode {
3133 unsafe { mem::transmute(ffi::glfwGetInputMode(self.ptr, ffi::CURSOR)) }
3134 }
3135
3136 pub fn set_cursor_mode(&mut self, mode: CursorMode) {
3138 unsafe {
3139 ffi::glfwSetInputMode(self.ptr, ffi::CURSOR, mode as c_int);
3140 }
3141 }
3142
3143 pub fn set_cursor(&mut self, cursor: Option<Cursor>) -> Option<Cursor> {
3150 let previous = mem::replace(&mut self.current_cursor, cursor);
3151
3152 unsafe {
3153 ffi::glfwSetCursor(
3154 self.ptr,
3155 match self.current_cursor {
3156 Some(ref cursor) => cursor.ptr,
3157 None => ptr::null_mut(),
3158 },
3159 )
3160 }
3161
3162 previous
3163 }
3164
3165 #[cfg(feature = "image")]
3182 pub fn set_icon(&mut self, images: Vec<image::RgbaImage>) {
3183 let image_data: Vec<(Vec<_>, u32, u32)> = images
3186 .into_iter()
3187 .map(|image| {
3188 let (width, height) = image.dimensions();
3189
3190 (image.into_vec(), width, height)
3191 })
3192 .collect();
3193
3194 let glfw_images: Vec<ffi::GLFWimage> = image_data
3195 .iter()
3196 .map(|data| ffi::GLFWimage {
3197 width: data.1 as c_int,
3198 height: data.2 as c_int,
3199 pixels: data.0.as_ptr() as *const c_uchar,
3200 })
3201 .collect();
3202
3203 unsafe {
3204 ffi::glfwSetWindowIcon(
3205 self.ptr,
3206 glfw_images.len() as c_int,
3207 glfw_images.as_ptr() as *const ffi::GLFWimage,
3208 )
3209 }
3210 }
3211
3212 pub fn set_icon_from_pixels(&mut self, images: Vec<PixelImage>) {
3215 let glfw_images: Vec<ffi::GLFWimage> = images
3216 .iter()
3217 .map(|image: &PixelImage| ffi::GLFWimage {
3218 width: image.width as c_int,
3219 height: image.height as c_int,
3220 pixels: image.pixels.as_ptr() as *const c_uchar,
3221 })
3222 .collect();
3223
3224 unsafe {
3225 ffi::glfwSetWindowIcon(
3226 self.ptr,
3227 glfw_images.len() as c_int,
3228 glfw_images.as_ptr() as *const ffi::GLFWimage,
3229 )
3230 }
3231 }
3232
3233 pub fn has_sticky_keys(&self) -> bool {
3235 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::STICKY_KEYS) == ffi::TRUE }
3236 }
3237
3238 pub fn set_sticky_keys(&mut self, value: bool) {
3240 unsafe {
3241 ffi::glfwSetInputMode(self.ptr, ffi::STICKY_KEYS, value as c_int);
3242 }
3243 }
3244
3245 pub fn has_sticky_mouse_buttons(&self) -> bool {
3247 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::STICKY_MOUSE_BUTTONS) == ffi::TRUE }
3248 }
3249
3250 pub fn set_sticky_mouse_buttons(&mut self, value: bool) {
3252 unsafe {
3253 ffi::glfwSetInputMode(self.ptr, ffi::STICKY_MOUSE_BUTTONS, value as c_int);
3254 }
3255 }
3256
3257 pub fn does_store_lock_key_mods(&self) -> bool {
3259 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::LOCK_KEY_MODS) == ffi::TRUE }
3260 }
3261
3262 pub fn set_store_lock_key_mods(&mut self, value: bool) {
3264 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::LOCK_KEY_MODS, value as c_int) }
3265 }
3266
3267 pub fn uses_raw_mouse_motion(&self) -> bool {
3269 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::RAW_MOUSE_MOTION) == ffi::TRUE }
3270 }
3271
3272 pub fn set_raw_mouse_motion(&mut self, value: bool) {
3274 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::RAW_MOUSE_MOTION, value as c_int) }
3275 }
3276
3277 pub fn get_key(&self, key: Key) -> Action {
3279 unsafe { mem::transmute(ffi::glfwGetKey(self.ptr, key as c_int)) }
3280 }
3281
3282 pub fn get_mouse_button(&self, button: MouseButton) -> Action {
3284 unsafe { mem::transmute(ffi::glfwGetMouseButton(self.ptr, button as c_int)) }
3285 }
3286
3287 pub fn get_cursor_pos(&self) -> (f64, f64) {
3289 unsafe {
3290 let mut xpos = 0.0;
3291 let mut ypos = 0.0;
3292 ffi::glfwGetCursorPos(self.ptr, &mut xpos, &mut ypos);
3293 (xpos as f64, ypos as f64)
3294 }
3295 }
3296
3297 pub fn set_cursor_pos(&mut self, xpos: f64, ypos: f64) {
3299 unsafe {
3300 ffi::glfwSetCursorPos(self.ptr, xpos as c_double, ypos as c_double);
3301 }
3302 }
3303
3304 pub fn set_clipboard_string(&mut self, string: &str) {
3306 unsafe {
3307 with_c_str(string, |string| {
3308 ffi::glfwSetClipboardString(self.ptr, string);
3309 });
3310 }
3311 }
3312
3313 pub fn get_clipboard_string(&self) -> Option<String> {
3315 unsafe { string_from_nullable_c_str(ffi::glfwGetClipboardString(self.ptr)) }
3316 }
3317
3318 pub fn get_opacity(&self) -> f32 {
3320 unsafe { ffi::glfwGetWindowOpacity(self.ptr) }
3321 }
3322
3323 pub fn set_opacity(&mut self, opacity: f32) {
3325 unsafe { ffi::glfwSetWindowOpacity(self.ptr, opacity) }
3326 }
3327
3328 pub fn request_attention(&mut self) {
3330 unsafe { ffi::glfwRequestWindowAttention(self.ptr) }
3331 }
3332
3333 pub fn get_content_scale(&self) -> (f32, f32) {
3335 unsafe {
3336 let mut xscale = 0.0_f32;
3337 let mut yscale = 0.0_f32;
3338 ffi::glfwGetWindowContentScale(self.ptr, &mut xscale, &mut yscale);
3339 (xscale, yscale)
3340 }
3341 }
3342
3343 #[cfg(target_os = "windows")]
3345 pub fn get_win32_window(&self) -> *mut c_void {
3346 unsafe { ffi::glfwGetWin32Window(self.ptr) }
3347 }
3348
3349 #[cfg(target_os = "windows")]
3351 pub fn get_wgl_context(&self) -> *mut c_void {
3352 unsafe { ffi::glfwGetWGLContext(self.ptr) }
3353 }
3354
3355 #[cfg(target_os = "macos")]
3357 pub fn get_cocoa_window(&self) -> *mut c_void {
3358 unsafe { ffi::glfwGetCocoaWindow(self.ptr) }
3359 }
3360
3361 #[cfg(target_os = "macos")]
3363 pub fn get_nsgl_context(&self) -> *mut c_void {
3364 unsafe { ffi::glfwGetNSGLContext(self.ptr) }
3365 }
3366
3367 #[cfg(all(target_os = "linux", not(feature = "wayland")))]
3369 pub fn get_x11_window(&self) -> *mut c_void {
3370 unsafe { ffi::glfwGetX11Window(self.ptr) }
3371 }
3372
3373 #[cfg(all(target_os = "linux", feature = "wayland"))]
3375 pub fn get_wayland_window(&self) -> *mut c_void {
3376 unsafe { ffi::glfwGetWaylandWindow(self.ptr) }
3377 }
3378
3379 #[cfg(target_os = "linux")]
3381 pub fn get_glx_context(&self) -> *mut c_void {
3382 unsafe { ffi::glfwGetGLXContext(self.ptr) }
3383 }
3384}
3385
3386impl Drop for Window {
3387 fn drop(&mut self) {
3393 drop(self.drop_sender.take());
3394
3395 #[cfg(feature = "log")]
3397 if self.drop_receiver.try_recv() != Err(std::sync::mpsc::TryRecvError::Disconnected) {
3398 debug!("Attempted to drop a Window before the `RenderContext` was dropped.");
3399 debug!("Blocking until the `RenderContext` was dropped.");
3400 let _ = self.drop_receiver.recv();
3401 }
3402
3403 if !self.ptr.is_null() {
3404 unsafe {
3405 let _: Box<WindowCallbacks> =
3406 mem::transmute(ffi::glfwGetWindowUserPointer(self.ptr));
3407 }
3408 }
3409
3410 if !self.is_shared {
3411 unsafe {
3412 ffi::glfwDestroyWindow(self.ptr);
3413 }
3414 }
3415 }
3416}
3417
3418#[derive(Debug)]
3419#[repr(transparent)]
3420pub struct PRenderContext(Box<RenderContext>);
3421
3422impl Deref for PRenderContext {
3423 type Target = RenderContext;
3424 fn deref(&self) -> &Self::Target {
3425 self.0.deref()
3426 }
3427}
3428
3429impl DerefMut for PRenderContext {
3430 fn deref_mut(&mut self) -> &mut Self::Target {
3431 self.0.deref_mut()
3432 }
3433}
3434
3435unsafe impl Send for PRenderContext {}
3436unsafe impl Sync for PRenderContext {}
3437
3438#[cfg(feature = "raw-window-handle-v0-6")]
3439impl HasWindowHandle for PRenderContext {
3440 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3441 self.0.window_handle()
3442 }
3443}
3444
3445#[cfg(feature = "raw-window-handle-v0-6")]
3446impl HasDisplayHandle for PRenderContext {
3447 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
3448 self.0.display_handle()
3449 }
3450}
3451
3452#[derive(Debug)]
3454pub struct RenderContext {
3455 ptr: *mut ffi::GLFWwindow,
3456 glfw: Glfw,
3457 #[allow(dead_code)]
3460 drop_sender: Sender<()>,
3461}
3462
3463impl RenderContext {
3464 pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
3466 if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
3467 self.make_current();
3468 }
3469
3470 self.glfw.get_proc_address_raw(procname)
3471 }
3472
3473 #[cfg(feature = "vulkan")]
3475 pub fn get_instance_proc_address(&mut self, instance: vk::Instance, procname: &str) -> VkProc {
3476 self.glfw.get_instance_proc_address_raw(instance, procname)
3477 }
3478
3479 #[cfg(feature = "vulkan")]
3481 pub fn get_physical_device_presentation_support(
3482 &self,
3483 instance: vk::Instance,
3484 device: vk::PhysicalDevice,
3485 queue_family: u32,
3486 ) -> bool {
3487 self.glfw
3488 .get_physical_device_presentation_support_raw(instance, device, queue_family)
3489 }
3490
3491 #[cfg(feature = "vulkan")]
3493 pub fn create_window_surface(
3494 &self,
3495 instance: vk::Instance,
3496 allocator: *const vk::AllocationCallbacks<'_>,
3497 surface: *mut vk::SurfaceKHR,
3498 ) -> vk::Result {
3499 unsafe { ffi::glfwCreateWindowSurface(instance, self.ptr, allocator, surface) }
3500 }
3501}
3502
3503unsafe impl Send for RenderContext {}
3504
3505pub trait Context {
3507 fn window_ptr(&self) -> *mut ffi::GLFWwindow;
3509
3510 fn window_id(&self) -> WindowId {
3512 self.window_ptr() as WindowId
3513 }
3514
3515 fn swap_buffers(&mut self) {
3521 let ptr = self.window_ptr();
3522 unsafe {
3523 ffi::glfwSwapBuffers(ptr);
3524 }
3525 }
3526
3527 fn is_current(&self) -> bool {
3529 self.window_ptr() == unsafe { ffi::glfwGetCurrentContext() }
3530 }
3531
3532 fn make_current(&mut self) {
3534 let ptr = self.window_ptr();
3535 unsafe {
3536 ffi::glfwMakeContextCurrent(ptr);
3537 }
3538 }
3539
3540 fn should_close(&self) -> bool {
3542 let ptr = self.window_ptr();
3543 unsafe { ffi::glfwWindowShouldClose(ptr) == ffi::TRUE }
3544 }
3545
3546 fn set_should_close(&mut self, value: bool) {
3548 let ptr = self.window_ptr();
3549 unsafe {
3550 ffi::glfwSetWindowShouldClose(ptr, value as c_int);
3551 }
3552 }
3553
3554 fn post_empty_event(&self) {
3556 unsafe { ffi::glfwPostEmptyEvent() }
3557 }
3558}
3559
3560impl Context for Window {
3561 fn window_ptr(&self) -> *mut ffi::GLFWwindow {
3562 self.ptr
3563 }
3564}
3565
3566impl Context for RenderContext {
3567 fn window_ptr(&self) -> *mut ffi::GLFWwindow {
3568 self.ptr
3569 }
3570}
3571
3572#[cfg(feature = "raw-window-handle-v0-6")]
3573impl HasWindowHandle for Window {
3574 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3575 Ok(unsafe { WindowHandle::borrow_raw(raw_window_handle(self)) })
3576 }
3577}
3578
3579#[cfg(feature = "raw-window-handle-v0-6")]
3580impl HasWindowHandle for RenderContext {
3581 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3582 Ok(unsafe { WindowHandle::borrow_raw(raw_window_handle(self)) })
3583 }
3584}
3585
3586#[cfg(feature = "raw-window-handle-v0-6")]
3587impl HasDisplayHandle for Window {
3588 fn display_handle(&'_ self) -> Result<DisplayHandle<'_>, HandleError> {
3589 Ok(unsafe { DisplayHandle::borrow_raw(raw_display_handle()) })
3590 }
3591}
3592
3593#[cfg(feature = "raw-window-handle-v0-6")]
3594impl HasDisplayHandle for RenderContext {
3595 fn display_handle(&'_ self) -> Result<DisplayHandle<'_>, HandleError> {
3596 Ok(unsafe { DisplayHandle::borrow_raw(raw_display_handle()) })
3597 }
3598}
3599
3600#[cfg(feature = "raw-window-handle-v0-5")]
3601unsafe impl HasRawWindowHandle for Window {
3602 fn raw_window_handle(&self) -> RawWindowHandle {
3603 raw_window_handle(self)
3604 }
3605}
3606
3607#[cfg(feature = "raw-window-handle-v0-5")]
3608unsafe impl HasRawWindowHandle for RenderContext {
3609 fn raw_window_handle(&self) -> RawWindowHandle {
3610 raw_window_handle(self)
3611 }
3612}
3613
3614#[cfg(feature = "raw-window-handle-v0-5")]
3615unsafe impl HasRawDisplayHandle for Window {
3616 fn raw_display_handle(&self) -> RawDisplayHandle {
3617 raw_display_handle()
3618 }
3619}
3620
3621#[cfg(feature = "raw-window-handle-v0-5")]
3622unsafe impl HasRawDisplayHandle for RenderContext {
3623 fn raw_display_handle(&self) -> RawDisplayHandle {
3624 raw_display_handle()
3625 }
3626}
3627
3628#[cfg(feature = "raw-window-handle-v0-6")]
3629fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
3630 #[cfg(target_family = "windows")]
3631 {
3632 use std::num::NonZeroIsize;
3633
3634 use raw_window_handle::Win32WindowHandle;
3635 let (hwnd, hinstance): (*mut std::ffi::c_void, *mut std::ffi::c_void) = unsafe {
3636 let hwnd = ffi::glfwGetWin32Window(context.window_ptr());
3637 let hinstance: *mut c_void =
3638 winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null()) as _;
3639 (hwnd, hinstance as _)
3640 };
3641 let mut handle = Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
3642 handle.hinstance = NonZeroIsize::new(hinstance as isize);
3643 RawWindowHandle::Win32(handle)
3644 }
3645 #[cfg(all(
3646 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3647 not(feature = "wayland")
3648 ))]
3649 {
3650 use raw_window_handle::XlibWindowHandle;
3651 let window =
3652 unsafe { ffi::glfwGetX11Window(context.window_ptr()) as std::os::raw::c_ulong };
3653 RawWindowHandle::Xlib(XlibWindowHandle::new(window))
3654 }
3655 #[cfg(all(
3656 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3657 feature = "wayland"
3658 ))]
3659 {
3660 use std::ptr::NonNull;
3661
3662 use raw_window_handle::WaylandWindowHandle;
3663 let surface = unsafe { ffi::glfwGetWaylandWindow(context.window_ptr()) };
3664 let handle = WaylandWindowHandle::new(
3665 NonNull::new(surface).expect("wayland window surface is null"),
3666 );
3667 RawWindowHandle::Wayland(handle)
3668 }
3669 #[cfg(target_os = "macos")]
3670 {
3671 use std::ptr::NonNull;
3672
3673 use objc2::msg_send_id;
3674 use objc2::rc::Id;
3675 use objc2::runtime::NSObject;
3676 use raw_window_handle::AppKitWindowHandle;
3677 let ns_window: *mut NSObject =
3678 unsafe { ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _ };
3679 let ns_view: Option<Id<NSObject>> = unsafe { msg_send_id![ns_window, contentView] };
3680 let ns_view = ns_view.expect("failed to access contentView on GLFW NSWindow");
3681 let ns_view: NonNull<NSObject> = NonNull::from(&*ns_view);
3682 let handle = AppKitWindowHandle::new(ns_view.cast());
3683 RawWindowHandle::AppKit(handle)
3684 }
3685 #[cfg(target_os = "emscripten")]
3686 {
3687 let _ = context; let mut wh = raw_window_handle::WebWindowHandle::new(1);
3689 RawWindowHandle::Web(wh)
3693 }
3694}
3695
3696#[cfg(feature = "raw-window-handle-v0-6")]
3697fn raw_display_handle() -> RawDisplayHandle {
3698 #[cfg(target_family = "windows")]
3699 {
3700 use raw_window_handle::WindowsDisplayHandle;
3701 RawDisplayHandle::Windows(WindowsDisplayHandle::new())
3702 }
3703 #[cfg(all(
3704 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3705 not(feature = "wayland")
3706 ))]
3707 {
3708 use std::ptr::NonNull;
3709
3710 use raw_window_handle::XlibDisplayHandle;
3711 let display = NonNull::new(unsafe { ffi::glfwGetX11Display() });
3712 let handle = XlibDisplayHandle::new(display, 0);
3713 RawDisplayHandle::Xlib(handle)
3714 }
3715 #[cfg(all(
3716 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3717 feature = "wayland"
3718 ))]
3719 {
3720 use std::ptr::NonNull;
3721
3722 use raw_window_handle::WaylandDisplayHandle;
3723 let display =
3724 NonNull::new(unsafe { ffi::glfwGetWaylandDisplay() }).expect("wayland display is null");
3725 let handle = WaylandDisplayHandle::new(display);
3726 RawDisplayHandle::Wayland(handle)
3727 }
3728 #[cfg(target_os = "macos")]
3729 {
3730 use raw_window_handle::AppKitDisplayHandle;
3731 RawDisplayHandle::AppKit(AppKitDisplayHandle::new())
3732 }
3733 #[cfg(target_os = "emscripten")]
3734 {
3735 RawDisplayHandle::Web(raw_window_handle::WebDisplayHandle::new())
3736 }
3737}
3738
3739#[cfg(feature = "raw-window-handle-v0-5")]
3740fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
3741 #[cfg(target_family = "windows")]
3742 {
3743 use raw_window_handle::Win32WindowHandle;
3744 let (hwnd, hinstance) = unsafe {
3745 let hwnd = ffi::glfwGetWin32Window(context.window_ptr());
3746 let hinstance = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null());
3747 (hwnd, hinstance as _)
3748 };
3749 let mut handle = Win32WindowHandle::empty();
3750 handle.hwnd = hwnd;
3751 handle.hinstance = hinstance;
3752 RawWindowHandle::Win32(handle)
3753 }
3754 #[cfg(all(
3755 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3756 not(feature = "wayland")
3757 ))]
3758 {
3759 use raw_window_handle::XlibWindowHandle;
3760 let mut handle = XlibWindowHandle::empty();
3761 handle.window =
3762 unsafe { ffi::glfwGetX11Window(context.window_ptr()) as std::os::raw::c_ulong };
3763 RawWindowHandle::Xlib(handle)
3764 }
3765 #[cfg(all(
3766 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3767 feature = "wayland"
3768 ))]
3769 {
3770 use raw_window_handle::WaylandWindowHandle;
3771 let mut handle = WaylandWindowHandle::empty();
3772 handle.surface = unsafe { ffi::glfwGetWaylandWindow(context.window_ptr()) };
3773 RawWindowHandle::Wayland(handle)
3774 }
3775 #[cfg(target_os = "macos")]
3776 {
3777 use raw_window_handle::AppKitWindowHandle;
3778 let (ns_window, ns_view) = unsafe {
3779 let ns_window: *mut objc::runtime::Object =
3780 ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _;
3781 let ns_view: *mut objc::runtime::Object = objc::msg_send![ns_window, contentView];
3782 assert_ne!(ns_view, std::ptr::null_mut());
3783 (
3784 ns_window as *mut std::ffi::c_void,
3785 ns_view as *mut std::ffi::c_void,
3786 )
3787 };
3788 let mut handle = AppKitWindowHandle::empty();
3789 handle.ns_window = ns_window;
3790 handle.ns_view = ns_view;
3791 RawWindowHandle::AppKit(handle)
3792 }
3793 #[cfg(target_os = "emscripten")]
3794 {
3795 let _ = context; let mut wh = raw_window_handle::WebWindowHandle::empty();
3797 wh.id = 1;
3801 RawWindowHandle::Web(wh)
3802 }
3803}
3804
3805#[cfg(feature = "raw-window-handle-v0-5")]
3806fn raw_display_handle() -> RawDisplayHandle {
3807 #[cfg(target_family = "windows")]
3808 {
3809 use raw_window_handle::WindowsDisplayHandle;
3810 RawDisplayHandle::Windows(WindowsDisplayHandle::empty())
3811 }
3812 #[cfg(all(
3813 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3814 not(feature = "wayland")
3815 ))]
3816 {
3817 use raw_window_handle::XlibDisplayHandle;
3818 let mut handle = XlibDisplayHandle::empty();
3819 handle.display = unsafe { ffi::glfwGetX11Display() };
3820 RawDisplayHandle::Xlib(handle)
3821 }
3822 #[cfg(all(
3823 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3824 feature = "wayland"
3825 ))]
3826 {
3827 use raw_window_handle::WaylandDisplayHandle;
3828 let mut handle = WaylandDisplayHandle::empty();
3829 handle.display = unsafe { ffi::glfwGetWaylandDisplay() };
3830 RawDisplayHandle::Wayland(handle)
3831 }
3832 #[cfg(target_os = "macos")]
3833 {
3834 use raw_window_handle::AppKitDisplayHandle;
3835 RawDisplayHandle::AppKit(AppKitDisplayHandle::empty())
3836 }
3837 #[cfg(target_os = "emscripten")]
3838 {
3839 RawDisplayHandle::Web(raw_window_handle::WebDisplayHandle::empty())
3840 }
3841}
3842
3843pub fn make_context_current(context: Option<&dyn Context>) {
3845 match context {
3846 Some(ctx) => unsafe { ffi::glfwMakeContextCurrent(ctx.window_ptr()) },
3847 None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
3848 }
3849}
3850
3851#[repr(i32)]
3853#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
3854#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3855pub enum JoystickId {
3856 Joystick1 = ffi::JOYSTICK_1,
3857 Joystick2 = ffi::JOYSTICK_2,
3858 Joystick3 = ffi::JOYSTICK_3,
3859 Joystick4 = ffi::JOYSTICK_4,
3860 Joystick5 = ffi::JOYSTICK_5,
3861 Joystick6 = ffi::JOYSTICK_6,
3862 Joystick7 = ffi::JOYSTICK_7,
3863 Joystick8 = ffi::JOYSTICK_8,
3864 Joystick9 = ffi::JOYSTICK_9,
3865 Joystick10 = ffi::JOYSTICK_10,
3866 Joystick11 = ffi::JOYSTICK_11,
3867 Joystick12 = ffi::JOYSTICK_12,
3868 Joystick13 = ffi::JOYSTICK_13,
3869 Joystick14 = ffi::JOYSTICK_14,
3870 Joystick15 = ffi::JOYSTICK_15,
3871 Joystick16 = ffi::JOYSTICK_16,
3872}
3873
3874impl JoystickId {
3875 pub fn from_i32(n: i32) -> Option<JoystickId> {
3877 if (0..=ffi::JOYSTICK_LAST).contains(&n) {
3878 Some(unsafe { mem::transmute(n) })
3879 } else {
3880 None
3881 }
3882 }
3883}
3884
3885#[repr(i32)]
3887#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
3888#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3889pub enum GamepadButton {
3890 ButtonA = ffi::GAMEPAD_BUTTON_A,
3891 ButtonB = ffi::GAMEPAD_BUTTON_B,
3892 ButtonX = ffi::GAMEPAD_BUTTON_X,
3893 ButtonY = ffi::GAMEPAD_BUTTON_Y,
3894 ButtonLeftBumper = ffi::GAMEPAD_BUTTON_LEFT_BUMPER,
3895 ButtonRightBumper = ffi::GAMEPAD_BUTTON_RIGHT_BUMPER,
3896 ButtonBack = ffi::GAMEPAD_BUTTON_BACK,
3897 ButtonStart = ffi::GAMEPAD_BUTTON_START,
3898 ButtonGuide = ffi::GAMEPAD_BUTTON_GUIDE,
3899 ButtonLeftThumb = ffi::GAMEPAD_BUTTON_LEFT_THUMB,
3900 ButtonRightThumb = ffi::GAMEPAD_BUTTON_RIGHT_THUMB,
3901 ButtonDpadUp = ffi::GAMEPAD_BUTTON_DPAD_UP,
3902 ButtonDpadRight = ffi::GAMEPAD_BUTTON_DPAD_RIGHT,
3903 ButtonDpadDown = ffi::GAMEPAD_BUTTON_DPAD_DOWN,
3904 ButtonDpadLeft = ffi::GAMEPAD_BUTTON_DPAD_LEFT,
3905}
3906
3907impl GamepadButton {
3908 pub fn from_i32(n: i32) -> Option<GamepadButton> {
3910 if (0..=ffi::GAMEPAD_BUTTON_LAST).contains(&n) {
3911 Some(unsafe { mem::transmute(n) })
3912 } else {
3913 None
3914 }
3915 }
3916}
3917
3918#[repr(i32)]
3920#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
3921#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3922pub enum GamepadAxis {
3923 AxisLeftX = ffi::GAMEPAD_AXIS_LEFT_X,
3924 AxisLeftY = ffi::GAMEPAD_AXIS_LEFT_Y,
3925 AxisRightX = ffi::GAMEPAD_AXIS_RIGHT_X,
3926 AxisRightY = ffi::GAMEPAD_AXIS_RIGHT_Y,
3927 AxisLeftTrigger = ffi::GAMEPAD_AXIS_LEFT_TRIGGER,
3928 AxisRightTrigger = ffi::GAMEPAD_AXIS_RIGHT_TRIGGER,
3929}
3930
3931impl GamepadAxis {
3932 pub fn from_i32(n: i32) -> Option<GamepadAxis> {
3934 if (0..=ffi::GAMEPAD_AXIS_LAST).contains(&n) {
3935 Some(unsafe { mem::transmute(n) })
3936 } else {
3937 None
3938 }
3939 }
3940}
3941
3942bitflags! {
3943 #[doc = "Joystick hats."]
3944 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3945 pub struct JoystickHats: ::std::os::raw::c_int {
3946 const Centered = crate::ffi::HAT_CENTERED;
3947 const Up = crate::ffi::HAT_UP;
3948 const Right = crate::ffi::HAT_RIGHT;
3949 const Down = crate::ffi::HAT_DOWN;
3950 const Left = crate::ffi::HAT_LEFT;
3951 }
3952}
3953
3954#[derive(Clone, Debug)]
3956pub struct Joystick {
3957 pub id: JoystickId,
3958 pub glfw: Glfw,
3959}
3960
3961#[derive(Copy, Clone, Debug)]
3963#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3964pub struct GamepadState {
3965 buttons: [Action; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize],
3966 axes: [f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize],
3967}
3968
3969#[repr(i32)]
3971#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
3972#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3973pub enum JoystickEvent {
3974 Connected = ffi::CONNECTED,
3975 Disconnected = ffi::DISCONNECTED,
3976}
3977
3978impl Joystick {
3979 pub fn is_present(&self) -> bool {
3981 unsafe { ffi::glfwJoystickPresent(self.id as c_int) == ffi::TRUE }
3982 }
3983
3984 pub fn get_axes(&self) -> Vec<f32> {
3986 unsafe {
3987 let mut count = 0;
3988 let ptr = ffi::glfwGetJoystickAxes(self.id as c_int, &mut count);
3989 slice::from_raw_parts(ptr, count as usize)
3990 .iter()
3991 .map(|&a| a as f32)
3992 .collect()
3993 }
3994 }
3995
3996 pub fn get_buttons(&self) -> Vec<c_int> {
3998 unsafe {
3999 let mut count = 0;
4000 let ptr = ffi::glfwGetJoystickButtons(self.id as c_int, &mut count);
4001 slice::from_raw_parts(ptr, count as usize)
4002 .iter()
4003 .map(|&b| b as c_int)
4004 .collect()
4005 }
4006 }
4007
4008 pub fn get_hats(&self) -> Vec<JoystickHats> {
4010 unsafe {
4011 let mut count = 0;
4012 let ptr = ffi::glfwGetJoystickHats(self.id as c_int, &mut count);
4013 slice::from_raw_parts(ptr, count as usize)
4014 .iter()
4015 .map(|&b| mem::transmute(b as c_int))
4016 .collect()
4017 }
4018 }
4019
4020 pub fn get_name(&self) -> Option<String> {
4022 unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickName(self.id as c_int)) }
4023 }
4024
4025 pub fn get_guid(&self) -> Option<String> {
4027 unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickGUID(self.id as c_int)) }
4028 }
4029
4030 pub fn is_gamepad(&self) -> bool {
4032 unsafe { ffi::glfwJoystickIsGamepad(self.id as c_int) == ffi::TRUE }
4033 }
4034
4035 pub fn get_gamepad_name(&self) -> Option<String> {
4037 unsafe { string_from_nullable_c_str(ffi::glfwGetGamepadName(self.id as c_int)) }
4038 }
4039
4040 pub fn get_gamepad_state(&self) -> Option<GamepadState> {
4042 unsafe {
4043 let mut state = ffi::GLFWgamepadstate {
4044 buttons: [0; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize],
4045 axes: [0_f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize],
4046 };
4047 if ffi::glfwGetGamepadState(self.id as c_int, &mut state) == ffi::TRUE {
4048 Some(state.into())
4049 } else {
4050 None
4051 }
4052 }
4053 }
4054}
4055
4056impl From<ffi::GLFWgamepadstate> for GamepadState {
4057 fn from(state: ffi::GLFWgamepadstate) -> Self {
4058 let mut buttons = [Action::Release; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize];
4059 let mut axes = [0_f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize];
4060 unsafe {
4061 state
4062 .buttons
4063 .iter()
4064 .map(|&b| mem::transmute(b as c_int))
4065 .zip(buttons.iter_mut())
4066 .for_each(|(a, b)| *b = a);
4067 }
4068 state
4069 .axes
4070 .iter()
4071 .map(|&f| f as f32)
4072 .zip(axes.iter_mut())
4073 .for_each(|(a, b)| *b = a);
4074 Self { buttons, axes }
4075 }
4076}
4077
4078impl GamepadState {
4079 pub fn get_button_state(&self, button: GamepadButton) -> Action {
4080 self.buttons[button as usize]
4081 }
4082
4083 pub fn get_axis(&self, axis: GamepadAxis) -> f32 {
4084 self.axes[axis as usize]
4085 }
4086}
4087
4088#[inline(always)]
4089fn unwrap_dont_care(value: Option<u32>) -> c_int {
4090 match value {
4091 Some(v) => v as c_int,
4092 None => ffi::DONT_CARE,
4093 }
4094}