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
33pub mod ffi {
84 pub use glfw_sys::*;
85}
86macro_rules! make_user_callback_functions {
87 (
88 doc -> $doc:literal,
89 set -> $set:ident,
90 unset -> $unset:ident,
91 poll -> $poll:ident,
92 callback_field -> $callback_field:ident,
93 poll_field -> $poll_field:ident,
94 glfw -> $glfw:ident,
95 args -> ($($args:ty),*),
96 secret -> $secret:ident
97 ) => {
98
99 #[doc = $doc]
100 pub fn $set<T>(&mut self, callback: T)
101 where T: FnMut(&mut Window, $($args),*) + 'static {
102 unsafe {
103 let callbacks = WindowCallbacks::get_callbacks(self.ptr);
104 callbacks.$callback_field = Some(Box::new(callback));
105 ffi::$glfw(self.ptr, Some(Self::$secret));
106 }
107 }
108
109 #[doc = $doc]
110 pub fn $unset(&mut self) {
111 unsafe {
112 let callbacks = WindowCallbacks::get_callbacks(self.ptr);
113 callbacks.$callback_field = None;
114
115 if !callbacks.$poll_field {
117 ffi::$glfw(self.ptr, None);
118 }
119 }
120 }
121
122 #[doc = $doc]
123 pub fn $poll(&mut self, should_poll: bool) {
124 unsafe {
125 let callbacks = WindowCallbacks::get_callbacks(self.ptr);
126 callbacks.$poll_field = should_poll;
127
128 if should_poll {
130 ffi::$glfw(self.ptr, Some(Self::$secret));
131 } else if callbacks.$callback_field.is_none() {
132 ffi::$glfw(self.ptr, None);
133 }
134 }
135 }
136 }
137}
138
139macro_rules! new_callback {
140 (
141 doc -> $doc:literal,
142 set -> $set:ident,
143 unset -> $unset:ident,
144 poll -> $poll:ident,
145 callback_field -> $callback_field:ident,
146 poll_field -> $poll_field:ident,
147 window_event -> $window_event:ident ($($args:ty),+),
148 glfw -> $glfw:ident ($($glfw_arg_names:ident: $glfw_args:ty),*),
149 convert_args -> ($($convert_args:expr),*),
150 secret -> $secret:ident
151 ) => {
152
153 #[allow(unused_unsafe)]
154 extern "C" fn $secret(glfw_window: *mut GLFWwindow, $($glfw_arg_names: $glfw_args),*) {
155 unsafe {
156 let callbacks = WindowCallbacks::get_callbacks(glfw_window);
157 let window = &mut *callbacks.window_ptr;
158 if let Some(func) = &mut callbacks.$callback_field {
159 func(window, $($convert_args),*);
160 }
161 if callbacks.$poll_field {
162 let event = (ffi::glfwGetTime() as f64, WindowEvent::$window_event($($convert_args),*));
163 if let Some(event) = callbacks::unbuffered::handle(glfw_window as WindowId, event) {
164 callbacks.sender.send(event);
165 }
166 }
167 }
168 }
169
170 make_user_callback_functions!(
171 doc -> $doc,
172 set -> $set,
173 unset -> $unset,
174 poll -> $poll,
175 callback_field -> $callback_field,
176 poll_field -> $poll_field,
177 glfw -> $glfw,
178 args -> ($($args),*),
179 secret -> $secret
180 );
181 };
182 (
183 doc -> $doc:literal,
184 set -> $set:ident,
185 unset -> $unset:ident,
186 poll -> $poll:ident,
187 callback_field -> $callback_field:ident,
188 poll_field -> $poll_field:ident,
189 window_event -> $window_event:ident,
190 glfw -> $glfw:ident ($($glfw_arg_names:ident: $glfw_args:ty),*),
191 convert_args -> ($($convert_args:expr),*),
192 secret -> $secret:ident
193 ) => {
194
195 #[allow(unused_unsafe)]
196 extern "C" fn $secret(glfw_window: *mut GLFWwindow, $($glfw_arg_names: $glfw_args),*) {
197 unsafe {
198 let callbacks = WindowCallbacks::get_callbacks(glfw_window);
199 let window = &mut *callbacks.window_ptr;
200 if let Some(func) = &mut callbacks.$callback_field {
201 func(window);
202 }
203 if callbacks.$poll_field {
204 let event = (ffi::glfwGetTime() as f64, WindowEvent::$window_event);
205 if let Some(event) = callbacks::unbuffered::handle(glfw_window as WindowId, event) {
206 callbacks.sender.send(event);
207 }
208 }
209 }
210 }
211
212 make_user_callback_functions!(
213 doc -> $doc,
214 set -> $set,
215 unset -> $unset,
216 poll -> $poll,
217 callback_field -> $callback_field,
218 poll_field -> $poll_field,
219 glfw -> $glfw,
220 args -> (),
221 secret -> $secret
222 );
223 }
224}
225
226#[cfg(feature = "log")]
227#[macro_use]
228extern crate log;
229#[macro_use]
230extern crate bitflags;
231#[cfg(feature = "image")]
232#[allow(unused)]
233extern crate image;
234
235#[cfg(feature = "raw-window-handle-v0-6")]
236extern crate raw_window_handle_0_6 as raw_window_handle;
237
238#[cfg(feature = "raw-window-handle-v0-5")]
239extern crate raw_window_handle_0_5 as raw_window_handle;
240
241use std::collections::VecDeque;
242#[allow(unused)]
243use std::ffi::*;
244use std::ffi::{CStr, CString};
245use std::marker::Send;
246use std::ops::{Deref, DerefMut};
247#[cfg(not(target_os = "emscripten"))]
248use std::os::raw::c_void;
249use std::os::raw::{c_char, c_double, c_float, c_int, c_ushort};
250use std::path::PathBuf;
251use std::ptr::{null, null_mut};
252use std::sync::atomic::{AtomicUsize, Ordering};
253use std::sync::mpsc::{channel, Receiver, Sender};
254use std::sync::{Arc, Mutex};
255use std::{error, fmt, mem, ptr, slice};
256
257#[cfg(feature = "raw-window-handle-v0-6")]
258use raw_window_handle::{
259 DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
260};
261#[cfg(feature = "raw-window-handle-v0-5")]
262use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
263use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
264#[cfg(feature = "serde")]
265use serde::{Deserialize, Serialize};
266
267pub use self::MouseButton::Button1 as MouseButtonLeft;
269pub use self::MouseButton::Button2 as MouseButtonRight;
271pub use self::MouseButton::Button3 as MouseButtonMiddle;
273use crate::ffi::GLFWwindow;
274
275mod callbacks;
276
277#[derive(Debug)]
278#[repr(transparent)]
279pub struct PWindow(Box<Window>);
280
281impl PWindow {
282 fn raw_ptr(&mut self) -> *mut Window {
283 self.0.deref_mut()
284 }
285}
286
287impl Deref for PWindow {
288 type Target = Window;
289 fn deref(&self) -> &Self::Target {
290 self.0.deref()
291 }
292}
293
294impl DerefMut for PWindow {
295 fn deref_mut(&mut self) -> &mut Self::Target {
296 self.0.deref_mut()
297 }
298}
299
300unsafe impl Send for PWindow {}
301
302unsafe impl Sync for PWindow {}
303
304#[cfg(feature = "raw-window-handle-v0-6")]
306impl HasWindowHandle for PWindow {
307 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
308 self.0.window_handle()
309 }
310}
311
312#[cfg(feature = "raw-window-handle-v0-6")]
313impl HasDisplayHandle for PWindow {
314 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
315 self.0.display_handle()
316 }
317}
318
319pub type WindowId = usize;
321
322#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
323#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
324pub struct Version {
325 pub major: u64,
326 pub minor: u64,
327 pub patch: u64,
328}
329
330#[repr(i32)]
332#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
333#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
334pub enum Action {
335 Release = ffi::GLFW_RELEASE,
336 Press = ffi::GLFW_PRESS,
337 Repeat = ffi::GLFW_REPEAT,
338}
339
340#[repr(i32)]
342#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
343#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
344pub enum Key {
345 Space = ffi::GLFW_KEY_SPACE,
346 Apostrophe = ffi::GLFW_KEY_APOSTROPHE,
347 Comma = ffi::GLFW_KEY_COMMA,
348 Minus = ffi::GLFW_KEY_MINUS,
349 Period = ffi::GLFW_KEY_PERIOD,
350 Slash = ffi::GLFW_KEY_SLASH,
351 Num0 = ffi::GLFW_KEY_0,
352 Num1 = ffi::GLFW_KEY_1,
353 Num2 = ffi::GLFW_KEY_2,
354 Num3 = ffi::GLFW_KEY_3,
355 Num4 = ffi::GLFW_KEY_4,
356 Num5 = ffi::GLFW_KEY_5,
357 Num6 = ffi::GLFW_KEY_6,
358 Num7 = ffi::GLFW_KEY_7,
359 Num8 = ffi::GLFW_KEY_8,
360 Num9 = ffi::GLFW_KEY_9,
361 Semicolon = ffi::GLFW_KEY_SEMICOLON,
362 Equal = ffi::GLFW_KEY_EQUAL,
363 A = ffi::GLFW_KEY_A,
364 B = ffi::GLFW_KEY_B,
365 C = ffi::GLFW_KEY_C,
366 D = ffi::GLFW_KEY_D,
367 E = ffi::GLFW_KEY_E,
368 F = ffi::GLFW_KEY_F,
369 G = ffi::GLFW_KEY_G,
370 H = ffi::GLFW_KEY_H,
371 I = ffi::GLFW_KEY_I,
372 J = ffi::GLFW_KEY_J,
373 K = ffi::GLFW_KEY_K,
374 L = ffi::GLFW_KEY_L,
375 M = ffi::GLFW_KEY_M,
376 N = ffi::GLFW_KEY_N,
377 O = ffi::GLFW_KEY_O,
378 P = ffi::GLFW_KEY_P,
379 Q = ffi::GLFW_KEY_Q,
380 R = ffi::GLFW_KEY_R,
381 S = ffi::GLFW_KEY_S,
382 T = ffi::GLFW_KEY_T,
383 U = ffi::GLFW_KEY_U,
384 V = ffi::GLFW_KEY_V,
385 W = ffi::GLFW_KEY_W,
386 X = ffi::GLFW_KEY_X,
387 Y = ffi::GLFW_KEY_Y,
388 Z = ffi::GLFW_KEY_Z,
389 LeftBracket = ffi::GLFW_KEY_LEFT_BRACKET,
390 Backslash = ffi::GLFW_KEY_BACKSLASH,
391 RightBracket = ffi::GLFW_KEY_RIGHT_BRACKET,
392 GraveAccent = ffi::GLFW_KEY_GRAVE_ACCENT,
393 World1 = ffi::GLFW_KEY_WORLD_1,
394 World2 = ffi::GLFW_KEY_WORLD_2,
395
396 Escape = ffi::GLFW_KEY_ESCAPE,
397 Enter = ffi::GLFW_KEY_ENTER,
398 Tab = ffi::GLFW_KEY_TAB,
399 Backspace = ffi::GLFW_KEY_BACKSPACE,
400 Insert = ffi::GLFW_KEY_INSERT,
401 Delete = ffi::GLFW_KEY_DELETE,
402 Right = ffi::GLFW_KEY_RIGHT,
403 Left = ffi::GLFW_KEY_LEFT,
404 Down = ffi::GLFW_KEY_DOWN,
405 Up = ffi::GLFW_KEY_UP,
406 PageUp = ffi::GLFW_KEY_PAGE_UP,
407 PageDown = ffi::GLFW_KEY_PAGE_DOWN,
408 Home = ffi::GLFW_KEY_HOME,
409 End = ffi::GLFW_KEY_END,
410 CapsLock = ffi::GLFW_KEY_CAPS_LOCK,
411 ScrollLock = ffi::GLFW_KEY_SCROLL_LOCK,
412 NumLock = ffi::GLFW_KEY_NUM_LOCK,
413 PrintScreen = ffi::GLFW_KEY_PRINT_SCREEN,
414 Pause = ffi::GLFW_KEY_PAUSE,
415 F1 = ffi::GLFW_KEY_F1,
416 F2 = ffi::GLFW_KEY_F2,
417 F3 = ffi::GLFW_KEY_F3,
418 F4 = ffi::GLFW_KEY_F4,
419 F5 = ffi::GLFW_KEY_F5,
420 F6 = ffi::GLFW_KEY_F6,
421 F7 = ffi::GLFW_KEY_F7,
422 F8 = ffi::GLFW_KEY_F8,
423 F9 = ffi::GLFW_KEY_F9,
424 F10 = ffi::GLFW_KEY_F10,
425 F11 = ffi::GLFW_KEY_F11,
426 F12 = ffi::GLFW_KEY_F12,
427 F13 = ffi::GLFW_KEY_F13,
428 F14 = ffi::GLFW_KEY_F14,
429 F15 = ffi::GLFW_KEY_F15,
430 F16 = ffi::GLFW_KEY_F16,
431 F17 = ffi::GLFW_KEY_F17,
432 F18 = ffi::GLFW_KEY_F18,
433 F19 = ffi::GLFW_KEY_F19,
434 F20 = ffi::GLFW_KEY_F20,
435 F21 = ffi::GLFW_KEY_F21,
436 F22 = ffi::GLFW_KEY_F22,
437 F23 = ffi::GLFW_KEY_F23,
438 F24 = ffi::GLFW_KEY_F24,
439 F25 = ffi::GLFW_KEY_F25,
440 Kp0 = ffi::GLFW_KEY_KP_0,
441 Kp1 = ffi::GLFW_KEY_KP_1,
442 Kp2 = ffi::GLFW_KEY_KP_2,
443 Kp3 = ffi::GLFW_KEY_KP_3,
444 Kp4 = ffi::GLFW_KEY_KP_4,
445 Kp5 = ffi::GLFW_KEY_KP_5,
446 Kp6 = ffi::GLFW_KEY_KP_6,
447 Kp7 = ffi::GLFW_KEY_KP_7,
448 Kp8 = ffi::GLFW_KEY_KP_8,
449 Kp9 = ffi::GLFW_KEY_KP_9,
450 KpDecimal = ffi::GLFW_KEY_KP_DECIMAL,
451 KpDivide = ffi::GLFW_KEY_KP_DIVIDE,
452 KpMultiply = ffi::GLFW_KEY_KP_MULTIPLY,
453 KpSubtract = ffi::GLFW_KEY_KP_SUBTRACT,
454 KpAdd = ffi::GLFW_KEY_KP_ADD,
455 KpEnter = ffi::GLFW_KEY_KP_ENTER,
456 KpEqual = ffi::GLFW_KEY_KP_EQUAL,
457 LeftShift = ffi::GLFW_KEY_LEFT_SHIFT,
458 LeftControl = ffi::GLFW_KEY_LEFT_CONTROL,
459 LeftAlt = ffi::GLFW_KEY_LEFT_ALT,
460 LeftSuper = ffi::GLFW_KEY_LEFT_SUPER,
461 RightShift = ffi::GLFW_KEY_RIGHT_SHIFT,
462 RightControl = ffi::GLFW_KEY_RIGHT_CONTROL,
463 RightAlt = ffi::GLFW_KEY_RIGHT_ALT,
464 RightSuper = ffi::GLFW_KEY_RIGHT_SUPER,
465 Menu = ffi::GLFW_KEY_MENU,
466 Unknown = ffi::GLFW_KEY_UNKNOWN,
467}
468
469pub fn get_key_name(key: Option<Key>, scancode: Option<Scancode>) -> Option<String> {
471 unsafe {
472 string_from_nullable_c_str(ffi::glfwGetKeyName(
473 match key {
474 Some(k) => k as c_int,
475 None => ffi::GLFW_KEY_UNKNOWN,
476 },
477 scancode.unwrap_or(ffi::GLFW_KEY_UNKNOWN),
478 ))
479 }
480}
481
482#[deprecated(
484 since = "0.16.0",
485 note = "'key_name' can cause a segfault, use 'get_key_name' instead"
486)]
487pub fn key_name(key: Option<Key>, scancode: Option<Scancode>) -> String {
488 unsafe {
489 string_from_c_str(ffi::glfwGetKeyName(
490 match key {
491 Some(k) => k as c_int,
492 None => ffi::GLFW_KEY_UNKNOWN,
493 },
494 scancode.unwrap_or(ffi::GLFW_KEY_UNKNOWN),
495 ))
496 }
497}
498
499pub fn get_key_scancode(key: Option<Key>) -> Option<Scancode> {
501 unsafe {
502 match ffi::glfwGetKeyScancode(match key {
503 Some(key) => key as c_int,
504 None => ffi::GLFW_KEY_UNKNOWN,
505 }) {
506 ffi::GLFW_KEY_UNKNOWN => None,
507 scancode => Some(scancode as Scancode),
508 }
509 }
510}
511
512impl Key {
513 #[deprecated(
515 since = "0.16.0",
516 note = "Key method 'name' can cause a segfault, use 'get_name' instead"
517 )]
518 pub fn name(&self) -> String {
519 #[allow(deprecated)]
520 key_name(Some(*self), None)
521 }
522
523 pub fn get_name(&self) -> Option<String> {
525 get_key_name(Some(*self), None)
526 }
527
528 pub fn get_scancode(&self) -> Option<Scancode> {
530 get_key_scancode(Some(*self))
531 }
532}
533
534#[repr(i32)]
537#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
538#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
539pub enum MouseButton {
540 Button1 = ffi::GLFW_MOUSE_BUTTON_1,
542 Button2 = ffi::GLFW_MOUSE_BUTTON_2,
544 Button3 = ffi::GLFW_MOUSE_BUTTON_3,
546 Button4 = ffi::GLFW_MOUSE_BUTTON_4,
547 Button5 = ffi::GLFW_MOUSE_BUTTON_5,
548 Button6 = ffi::GLFW_MOUSE_BUTTON_6,
549 Button7 = ffi::GLFW_MOUSE_BUTTON_7,
550 Button8 = ffi::GLFW_MOUSE_BUTTON_8,
551}
552
553impl MouseButton {
554 pub const Left: Self = MouseButton::Button1;
556 pub const Right: Self = MouseButton::Button2;
558 pub const Middle: Self = MouseButton::Button3;
560
561 pub fn from_i32(n: i32) -> Option<MouseButton> {
563 if (0..=ffi::GLFW_MOUSE_BUTTON_LAST).contains(&n) {
564 Some(unsafe { mem::transmute(n) })
565 } else {
566 None
567 }
568 }
569}
570
571pub struct DebugAliases<T>(pub T);
580
581impl fmt::Debug for DebugAliases<MouseButton> {
582 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583 let DebugAliases(button) = *self;
584 match button {
585 MouseButtonLeft => write!(f, "MouseButtonLeft"),
586 MouseButtonRight => write!(f, "MouseButtonRight"),
587 MouseButtonMiddle => write!(f, "MouseButtonMiddle"),
588 button => button.fmt(f),
589 }
590 }
591}
592
593#[repr(i32)]
595#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
596#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
597pub enum Error {
598 NoError = ffi::GLFW_NO_ERROR,
599 NotInitialized = ffi::GLFW_NOT_INITIALIZED,
600 NoCurrentContext = ffi::GLFW_NO_CURRENT_CONTEXT,
601 InvalidEnum = ffi::GLFW_INVALID_ENUM,
602 InvalidValue = ffi::GLFW_INVALID_VALUE,
603 OutOfMemory = ffi::GLFW_OUT_OF_MEMORY,
604 ApiUnavailable = ffi::GLFW_API_UNAVAILABLE,
605 VersionUnavailable = ffi::GLFW_VERSION_UNAVAILABLE,
606 PlatformError = ffi::GLFW_PLATFORM_ERROR,
607 FormatUnavailable = ffi::GLFW_FORMAT_UNAVAILABLE,
608 NoWindowContext = ffi::GLFW_NO_WINDOW_CONTEXT,
609}
610
611impl fmt::Display for Error {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 let description = match *self {
614 Error::NoError => "NoError",
615 Error::NotInitialized => "NotInitialized",
616 Error::NoCurrentContext => "NoCurrentContext",
617 Error::InvalidEnum => "InvalidEnum",
618 Error::InvalidValue => "InvalidValue",
619 Error::OutOfMemory => "OutOfMemory",
620 Error::ApiUnavailable => "ApiUnavailable",
621 Error::VersionUnavailable => "VersionUnavailable",
622 Error::PlatformError => "PlatformError",
623 Error::FormatUnavailable => "FormatUnavailable",
624 Error::NoWindowContext => "NoWindowContext",
625 };
626
627 f.write_str(description)
628 }
629}
630
631impl error::Error for Error {}
632
633pub fn fail_on_errors(e: Error, description: String) {
635 if e == Error::FormatUnavailable {
636 return;
642 }
643 panic!("GLFW Error: {}", description);
644}
645
646#[macro_export]
648macro_rules! fail_on_errors {
649 () => {{
650 |error, description| {
651 fail_on_errors(error, description);
652 }
653 }};
654}
655
656#[cfg(feature = "log")]
657pub fn log_errors(_: Error, description: String) {
659 error!("GLFW Error: {}", description);
660}
661
662#[cfg(not(feature = "log"))]
663pub fn log_errors(_: Error, description: String) {
665 eprintln!("GLFW Error: {}", description);
666}
667
668#[macro_export]
671macro_rules! log_errors {
672 () => {{
673 |error, description| {
674 log_errors(error, description);
675 }
676 }};
677}
678
679#[derive(Debug)]
682pub struct PixelImage {
683 pub width: u32,
685 pub height: u32,
687 pub pixels: Vec<u32>,
689}
690
691#[repr(i32)]
693#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
694#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
695pub enum CursorMode {
696 Normal = ffi::GLFW_CURSOR_NORMAL,
697 Hidden = ffi::GLFW_CURSOR_HIDDEN,
698 Captured = ffi::GLFW_CURSOR_CAPTURED,
699 Disabled = ffi::GLFW_CURSOR_DISABLED,
700}
701
702#[repr(i32)]
704#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
705#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
706pub enum StandardCursor {
707 Arrow = ffi::GLFW_ARROW_CURSOR,
709 IBeam = ffi::GLFW_IBEAM_CURSOR,
711 Crosshair = ffi::GLFW_CROSSHAIR_CURSOR,
713 Hand = ffi::GLFW_HAND_CURSOR,
715 HResize = ffi::GLFW_HRESIZE_CURSOR,
717 VResize = ffi::GLFW_VRESIZE_CURSOR,
719}
720
721#[derive(Debug)]
727pub struct Cursor {
728 ptr: *mut ffi::GLFWcursor,
729}
730
731impl Drop for Cursor {
732 fn drop(&mut self) {
733 unsafe { ffi::glfwDestroyCursor(self.ptr) }
734 }
735}
736
737impl Cursor {
738 pub fn standard(cursor: StandardCursor) -> Cursor {
740 Cursor {
741 ptr: unsafe { ffi::glfwCreateStandardCursor(cursor as c_int) },
742 }
743 }
744
745 #[cfg(feature = "image")]
754 pub fn create(image: image::RgbaImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
755 let (width, height) = image.dimensions();
756
757 let image_data = image.into_vec();
758
759 let glfw_image = ffi::GLFWimage {
760 width: width as c_int,
761 height: height as c_int,
762 pixels: image_data.as_ptr() as _,
763 };
764
765 Cursor {
766 ptr: unsafe {
767 ffi::glfwCreateCursor(
768 &glfw_image as *const ffi::GLFWimage,
769 x_hotspot as c_int,
770 y_hotspot as c_int,
771 )
772 },
773 }
774 }
775
776 pub fn create_from_pixels(image: PixelImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
785 let glfw_image = ffi::GLFWimage {
786 width: image.width as c_int,
787 height: image.height as c_int,
788 pixels: image.pixels.as_ptr() as _,
789 };
790
791 Cursor {
792 ptr: unsafe {
793 ffi::glfwCreateCursor(
794 &glfw_image as *const ffi::GLFWimage,
795 x_hotspot as c_int,
796 y_hotspot as c_int,
797 )
798 },
799 }
800 }
801}
802
803#[derive(Copy, Clone)]
805#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
806pub struct VidMode {
807 pub width: u32,
808 pub height: u32,
809 pub red_bits: u32,
810 pub green_bits: u32,
811 pub blue_bits: u32,
812 pub refresh_rate: u32,
813}
814
815#[derive(Debug)]
817#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
818pub struct GammaRamp {
819 pub red: Vec<c_ushort>,
820 pub green: Vec<c_ushort>,
821 pub blue: Vec<c_ushort>,
822}
823
824#[repr(i32)]
826#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
827#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
828pub enum ContextReleaseBehavior {
829 Any = ffi::GLFW_ANY_RELEASE_BEHAVIOR,
830 Flush = ffi::GLFW_RELEASE_BEHAVIOR_FLUSH,
833 None = ffi::GLFW_RELEASE_BEHAVIOR_NONE,
835}
836
837#[repr(i32)]
839#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
840#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
841pub enum ContextCreationApi {
842 Native = ffi::GLFW_NATIVE_CONTEXT_API,
843 Egl = ffi::GLFW_EGL_CONTEXT_API,
844 OsMesa = ffi::GLFW_OSMESA_CONTEXT_API,
845}
846
847#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
853#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
854pub enum SwapInterval {
855 None,
857 Adaptive,
860 Sync(u32),
862}
863
864pub type GLProc = ffi::GLFWglproc;
866
867#[cfg(feature = "vulkan")]
869pub type VkProc = ffi::GLFWvkproc;
870
871static REF_COUNT_FOR_GLFW: AtomicUsize = AtomicUsize::new(0);
874
875#[derive(Debug)]
877pub struct ThreadSafeGlfw {
878 glfw: Glfw,
879}
880
881impl ThreadSafeGlfw {
882 pub fn from(glfw: &mut Glfw) -> Self {
884 Self { glfw: glfw.clone() }
885 }
886
887 pub fn set_swap_interval(&mut self, interval: SwapInterval) {
889 self.glfw.set_swap_interval(interval);
890 }
891
892 pub fn extension_supported(&self, extension: &str) -> bool {
894 self.glfw.extension_supported(extension)
895 }
896
897 pub fn get_time(&self) -> f64 {
899 self.glfw.get_time()
900 }
901
902 pub fn set_time(&mut self, time: f64) {
904 self.glfw.set_time(time);
905 }
906
907 #[cfg(feature = "vulkan")]
909 pub fn vulkan_supported(&self) -> bool {
910 self.glfw.vulkan_supported()
911 }
912
913 #[cfg(feature = "vulkan")]
915 pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
916 self.glfw.get_required_instance_extensions()
917 }
918
919 #[cfg(feature = "vulkan")]
921 pub fn get_instance_proc_address_raw(
922 &self,
923 instance: ffi::VkInstance,
924 procname: &str,
925 ) -> VkProc {
926 self.glfw.get_instance_proc_address_raw(instance, procname)
927 }
928
929 #[cfg(feature = "vulkan")]
931 pub fn get_physical_device_presentation_support_raw(
932 &self,
933 instance: ffi::VkInstance,
934 device: ffi::VkPhysicalDevice,
935 queue_family: u32,
936 ) -> bool {
937 self.glfw
938 .get_physical_device_presentation_support_raw(instance, device, queue_family)
939 }
940
941 pub fn get_timer_value(&self) -> u64 {
943 self.glfw.get_timer_value()
944 }
945
946 pub fn get_timer_frequency(&self) -> u64 {
948 self.glfw.get_timer_frequency()
949 }
950
951 pub fn post_empty_event(&self) {
953 self.glfw.post_empty_event()
954 }
955}
956
957unsafe impl Send for ThreadSafeGlfw {}
958
959#[non_exhaustive]
965#[derive(Debug)]
966pub struct Glfw {
967 phantom: std::marker::PhantomData<*const ()>,
968}
969
970#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
972#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
973pub enum InitError {
974 AlreadyInitialized,
976 Internal,
978}
979
980impl fmt::Display for InitError {
981 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
982 let description = match *self {
983 InitError::AlreadyInitialized => "Already Initialized",
984 InitError::Internal => "Internal Initialization Error",
985 };
986
987 f.write_str(description)
988 }
989}
990
991impl error::Error for InitError {}
992
993#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
995#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
996pub enum InitHint {
997 Platform(Platform),
998 JoystickHatButtons(bool),
1001 CocoaChdirResources(bool),
1006 CocoaMenubar(bool),
1011}
1012
1013#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
1018#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1019#[repr(i32)]
1020pub enum Platform {
1021 X11 = ffi::GLFW_PLATFORM_X11,
1022 Wayland = ffi::GLFW_PLATFORM_WAYLAND,
1023 Win32 = ffi::GLFW_PLATFORM_WIN32,
1024 MacOS = ffi::GLFW_PLATFORM_COCOA,
1025 Null = ffi::GLFW_PLATFORM_NULL,
1027 Any = ffi::GLFW_ANY_PLATFORM,
1029}
1030impl Platform {
1031 pub fn is_supported(&self) -> bool {
1033 unsafe { ffi::glfwPlatformSupported(*self as c_int) == ffi::GLFW_TRUE }
1034 }
1035}
1036pub fn init_hint(hint: InitHint) {
1044 match hint {
1045 InitHint::Platform(platform) => unsafe {
1046 ffi::glfwInitHint(ffi::GLFW_PLATFORM, platform as c_int)
1047 },
1048 InitHint::JoystickHatButtons(joystick_hat_buttons) => unsafe {
1049 ffi::glfwInitHint(
1050 ffi::GLFW_JOYSTICK_HAT_BUTTONS,
1051 joystick_hat_buttons as c_int,
1052 )
1053 },
1054 InitHint::CocoaChdirResources(chdir) => unsafe {
1055 ffi::glfwInitHint(ffi::GLFW_COCOA_CHDIR_RESOURCES, chdir as c_int)
1056 },
1057 InitHint::CocoaMenubar(menubar) => unsafe {
1058 ffi::glfwInitHint(ffi::GLFW_COCOA_MENUBAR, menubar as c_int)
1059 },
1060 }
1061}
1062pub fn init<T>(callback: T) -> Result<Glfw, InitError>
1105where
1106 T: FnMut(Error, String) + 'static,
1107{
1108 callbacks::error::set(callback);
1112
1113 init_no_callbacks()
1114}
1115
1116pub fn init_no_callbacks() -> Result<Glfw, InitError> {
1117 if unsafe { ffi::glfwInit() } == ffi::GLFW_TRUE {
1121 REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
1122 Ok(Glfw {
1123 phantom: std::marker::PhantomData,
1124 })
1125 } else {
1126 Err(InitError::Internal)
1127 }
1128}
1129
1130impl Glfw {
1131 pub fn set_error_callback<T>(&mut self, callback: T)
1155 where
1156 T: FnMut(Error, String) + 'static,
1157 {
1158 callbacks::error::set(callback);
1159 }
1160
1161 pub fn unset_error_callback(&mut self) {
1163 callbacks::error::unset();
1164 }
1165
1166 pub fn set_monitor_callback<T>(&mut self, callback: T)
1168 where
1169 T: FnMut(Monitor, MonitorEvent) + 'static,
1170 {
1171 callbacks::monitor::set(callback);
1172 }
1173
1174 pub fn unset_monitor_callback(&mut self) {
1176 callbacks::monitor::unset();
1177 }
1178
1179 pub fn set_joystick_callback<T>(&mut self, callback: T)
1181 where
1182 T: FnMut(JoystickId, JoystickEvent) + 'static,
1183 {
1184 callbacks::joystick::set(callback);
1185 }
1186
1187 pub fn unset_joystick_callback(&mut self) {
1189 callbacks::joystick::unset();
1190 }
1191
1192 pub fn with_primary_monitor<T, F>(&mut self, f: F) -> T
1205 where
1206 F: FnOnce(&mut Self, Option<&mut Monitor>) -> T,
1207 {
1208 match unsafe { ffi::glfwGetPrimaryMonitor() } {
1209 ptr if ptr.is_null() => f(self, None),
1210 ptr => f(self, Some(&mut Monitor { ptr })),
1211 }
1212 }
1213
1214 pub fn with_window_monitor<T, F>(&mut self, window: &mut Window, f: F) -> T
1225 where
1226 F: FnOnce(&mut Self, Option<&mut Monitor>) -> T,
1227 {
1228 match unsafe { ffi::glfwGetWindowMonitor(window.ptr) } {
1229 ptr if ptr.is_null() => f(self, None),
1230 ptr => f(self, Some(&mut Monitor { ptr })),
1231 }
1232 }
1233
1234 pub fn with_connected_monitors<T, F>(&mut self, f: F) -> T
1247 where
1248 F: FnOnce(&mut Self, &[&mut Monitor]) -> T,
1249 {
1250 unsafe {
1251 let mut count = 0;
1252 let ptr = ffi::glfwGetMonitors(&mut count);
1253 let mut monitors;
1254 let refs: Vec<&mut Monitor> = if ptr.is_null() {
1255 Vec::new()
1256 } else {
1257 monitors = slice::from_raw_parts(ptr as *const _, count as usize)
1258 .iter()
1259 .map(|&ptr| Monitor { ptr })
1260 .collect::<Vec<Monitor>>();
1261 monitors.iter_mut().collect()
1262 };
1263 f(self, &refs)
1264 }
1265 }
1266
1267 #[cfg(feature = "vulkan")]
1269 pub fn vulkan_supported(&self) -> bool {
1270 unsafe { ffi::glfwVulkanSupported() == ffi::GLFW_TRUE }
1271 }
1272
1273 pub fn window_hint(&mut self, hint: WindowHint) {
1303 #[inline(always)]
1308 unsafe fn dont_care_hint(hint: c_int, value: Option<u32>) {
1309 ffi::glfwWindowHint(hint, unwrap_dont_care(value))
1310 }
1311
1312 #[inline(always)]
1313 unsafe fn string_hint(hint: c_int, value: Option<String>) {
1314 let value = if let Some(value) = &value {
1315 value.as_str()
1316 } else {
1317 ""
1318 };
1319 with_c_str(value, |value| ffi::glfwWindowHintString(hint, value))
1320 }
1321
1322 match hint {
1323 WindowHint::MousePassthrough(value) => unsafe {
1324 ffi::glfwWindowHint(ffi::GLFW_MOUSE_PASSTHROUGH, value as c_int)
1325 },
1326 WindowHint::RedBits(bits) => unsafe { dont_care_hint(ffi::GLFW_RED_BITS, bits) },
1327 WindowHint::GreenBits(bits) => unsafe { dont_care_hint(ffi::GLFW_GREEN_BITS, bits) },
1328 WindowHint::BlueBits(bits) => unsafe { dont_care_hint(ffi::GLFW_BLUE_BITS, bits) },
1329 WindowHint::AlphaBits(bits) => unsafe { dont_care_hint(ffi::GLFW_ALPHA_BITS, bits) },
1330 WindowHint::DepthBits(bits) => unsafe { dont_care_hint(ffi::GLFW_DEPTH_BITS, bits) },
1331 WindowHint::StencilBits(bits) => unsafe {
1332 dont_care_hint(ffi::GLFW_STENCIL_BITS, bits)
1333 },
1334 WindowHint::AccumRedBits(bits) => unsafe {
1335 dont_care_hint(ffi::GLFW_ACCUM_RED_BITS, bits)
1336 },
1337 WindowHint::AccumGreenBits(bits) => unsafe {
1338 dont_care_hint(ffi::GLFW_ACCUM_GREEN_BITS, bits)
1339 },
1340 WindowHint::AccumBlueBits(bits) => unsafe {
1341 dont_care_hint(ffi::GLFW_ACCUM_BLUE_BITS, bits)
1342 },
1343 WindowHint::AccumAlphaBits(bits) => unsafe {
1344 dont_care_hint(ffi::GLFW_ACCUM_ALPHA_BITS, bits)
1345 },
1346 WindowHint::AuxBuffers(num_buffers) => unsafe {
1347 dont_care_hint(ffi::GLFW_AUX_BUFFERS, num_buffers)
1348 },
1349 WindowHint::Samples(num_samples) => unsafe {
1350 dont_care_hint(ffi::GLFW_SAMPLES, num_samples)
1351 },
1352 WindowHint::RefreshRate(rate) => unsafe {
1353 dont_care_hint(ffi::GLFW_REFRESH_RATE, rate)
1354 },
1355 WindowHint::Stereo(is_stereo) => unsafe {
1356 ffi::glfwWindowHint(ffi::GLFW_STEREO, is_stereo as c_int)
1357 },
1358 WindowHint::SRgbCapable(is_capable) => unsafe {
1359 ffi::glfwWindowHint(ffi::GLFW_SRGB_CAPABLE, is_capable as c_int)
1360 },
1361 WindowHint::ClientApi(api) => unsafe {
1362 ffi::glfwWindowHint(ffi::GLFW_CLIENT_API, api as c_int)
1363 },
1364 WindowHint::ContextVersionMajor(major) => unsafe {
1365 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MAJOR, major as c_int)
1366 },
1367 WindowHint::ContextVersionMinor(minor) => unsafe {
1368 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MINOR, minor as c_int)
1369 },
1370 WindowHint::ContextVersion(major, minor) => unsafe {
1371 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MAJOR, major as c_int);
1372 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_VERSION_MINOR, minor as c_int)
1373 },
1374 WindowHint::ContextRobustness(robustness) => unsafe {
1375 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_ROBUSTNESS, robustness as c_int)
1376 },
1377 WindowHint::OpenGlForwardCompat(is_compat) => unsafe {
1378 ffi::glfwWindowHint(ffi::GLFW_OPENGL_FORWARD_COMPAT, is_compat as c_int)
1379 },
1380 WindowHint::OpenGlDebugContext(is_debug) => unsafe {
1381 ffi::glfwWindowHint(ffi::GLFW_OPENGL_DEBUG_CONTEXT, is_debug as c_int)
1382 },
1383 WindowHint::OpenGlProfile(profile) => unsafe {
1384 ffi::glfwWindowHint(ffi::GLFW_OPENGL_PROFILE, profile as c_int)
1385 },
1386 WindowHint::Resizable(is_resizable) => unsafe {
1387 ffi::glfwWindowHint(ffi::GLFW_RESIZABLE, is_resizable as c_int)
1388 },
1389 WindowHint::Visible(is_visible) => unsafe {
1390 ffi::glfwWindowHint(ffi::GLFW_VISIBLE, is_visible as c_int)
1391 },
1392 WindowHint::Decorated(is_decorated) => unsafe {
1393 ffi::glfwWindowHint(ffi::GLFW_DECORATED, is_decorated as c_int)
1394 },
1395 WindowHint::AutoIconify(auto_iconify) => unsafe {
1396 ffi::glfwWindowHint(ffi::GLFW_AUTO_ICONIFY, auto_iconify as c_int)
1397 },
1398 WindowHint::Floating(is_floating) => unsafe {
1399 ffi::glfwWindowHint(ffi::GLFW_FLOATING, is_floating as c_int)
1400 },
1401 WindowHint::Focused(is_focused) => unsafe {
1402 ffi::glfwWindowHint(ffi::GLFW_FOCUSED, is_focused as c_int)
1403 },
1404 WindowHint::Maximized(is_maximized) => unsafe {
1405 ffi::glfwWindowHint(ffi::GLFW_MAXIMIZED, is_maximized as c_int)
1406 },
1407 WindowHint::ContextNoError(is_no_error) => unsafe {
1408 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_NO_ERROR, is_no_error as c_int)
1409 },
1410 WindowHint::ContextCreationApi(api) => unsafe {
1411 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_CREATION_API, api as c_int)
1412 },
1413 WindowHint::ContextReleaseBehavior(behavior) => unsafe {
1414 ffi::glfwWindowHint(ffi::GLFW_CONTEXT_RELEASE_BEHAVIOR, behavior as c_int)
1415 },
1416 WindowHint::DoubleBuffer(is_dbuffered) => unsafe {
1417 ffi::glfwWindowHint(ffi::GLFW_DOUBLEBUFFER, is_dbuffered as c_int)
1418 },
1419 WindowHint::CenterCursor(center_cursor) => unsafe {
1420 ffi::glfwWindowHint(ffi::GLFW_CENTER_CURSOR, center_cursor as c_int)
1421 },
1422 WindowHint::TransparentFramebuffer(is_transparent) => unsafe {
1423 ffi::glfwWindowHint(ffi::GLFW_TRANSPARENT_FRAMEBUFFER, is_transparent as c_int)
1424 },
1425 WindowHint::FocusOnShow(focus) => unsafe {
1426 ffi::glfwWindowHint(ffi::GLFW_FOCUS_ON_SHOW, focus as c_int)
1427 },
1428 WindowHint::ScaleToMonitor(scale) => unsafe {
1429 ffi::glfwWindowHint(ffi::GLFW_SCALE_TO_MONITOR, scale as c_int)
1430 },
1431 WindowHint::CocoaRetinaFramebuffer(retina_fb) => unsafe {
1432 ffi::glfwWindowHint(ffi::GLFW_COCOA_RETINA_FRAMEBUFFER, retina_fb as c_int)
1433 },
1434 WindowHint::CocoaFrameName(name) => unsafe {
1435 string_hint(ffi::GLFW_COCOA_FRAME_NAME, name)
1436 },
1437 WindowHint::CocoaGraphicsSwitching(graphics_switching) => unsafe {
1438 ffi::glfwWindowHint(
1439 ffi::GLFW_COCOA_GRAPHICS_SWITCHING,
1440 graphics_switching as c_int,
1441 )
1442 },
1443 WindowHint::X11ClassName(class_name) => unsafe {
1444 string_hint(ffi::GLFW_X11_CLASS_NAME, class_name)
1445 },
1446 WindowHint::X11InstanceName(instance_name) => unsafe {
1447 string_hint(ffi::GLFW_X11_INSTANCE_NAME, instance_name)
1448 },
1449 }
1450 }
1451
1452 pub fn default_window_hints(&mut self) {
1457 unsafe {
1458 ffi::glfwDefaultWindowHints();
1459 }
1460 }
1461
1462 pub fn create_window(
1466 &mut self,
1467 width: u32,
1468 height: u32,
1469 title: &str,
1470 mode: WindowMode<'_>,
1471 ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
1472 #[cfg(feature = "wayland")]
1473 {
1474 self.window_hint(WindowHint::Focused(false));
1476 }
1477 self.create_window_intern(width, height, title, mode, None)
1478 }
1479
1480 fn create_window_intern(
1482 &self,
1483 width: u32,
1484 height: u32,
1485 title: &str,
1486 mode: WindowMode<'_>,
1487 share: Option<&Window>,
1488 ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
1489 let ptr = unsafe {
1490 with_c_str(title, |title| {
1491 ffi::glfwCreateWindow(
1492 width as c_int,
1493 height as c_int,
1494 title,
1495 mode.to_ptr(),
1496 match share {
1497 Some(w) => w.ptr,
1498 None => ptr::null_mut(),
1499 },
1500 )
1501 })
1502 };
1503 if ptr.is_null() {
1504 None
1505 } else {
1506 let (drop_sender, drop_receiver) = channel();
1507 let (sender, receiver) = glfw_channel(16, 256);
1508 let window = Window {
1509 ptr,
1510 glfw: self.clone(),
1511 is_shared: share.is_some(),
1512 drop_sender: Some(drop_sender),
1513 drop_receiver,
1514 current_cursor: None,
1515 };
1516 let mut callbacks = Box::new(WindowCallbacks::new(sender));
1517 let mut window = PWindow(Box::new(window));
1518
1519 unsafe {
1520 callbacks.window_ptr = window.raw_ptr();
1521 ffi::glfwSetWindowUserPointer(ptr, mem::transmute(callbacks));
1522 }
1523
1524 Some((window, receiver))
1525 }
1526 }
1527
1528 pub fn make_context_current(&mut self, context: Option<&Window>) {
1533 match context {
1534 Some(window) => unsafe { ffi::glfwMakeContextCurrent(window.ptr) },
1535 None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
1536 }
1537 }
1538
1539 #[cfg(all(not(target_os = "windows"), not(target_os = "macos"), feature = "x11"))]
1541 pub fn get_x11_display(&self) -> *mut c_void {
1542 unsafe { ffi::glfwGetX11Display() }
1543 }
1544
1545 #[cfg(all(
1547 not(target_os = "windows"),
1548 not(target_os = "macos"),
1549 feature = "wayland"
1550 ))]
1551 pub fn get_wayland_display(&self) -> *mut c_void {
1552 unsafe { ffi::glfwGetWaylandDisplay().cast_mut() }
1553 }
1554 pub fn get_platform(&self) -> Platform {
1556 unsafe { mem::transmute(ffi::glfwGetPlatform()) }
1557 }
1558 pub fn poll_events(&mut self) {
1562 unsafe {
1563 ffi::glfwPollEvents();
1564 }
1565 }
1566
1567 pub fn poll_events_unbuffered<F>(&mut self, mut f: F)
1575 where
1576 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1577 {
1578 let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1579 self.poll_events();
1580 }
1581
1582 pub fn wait_events(&mut self) {
1587 unsafe {
1588 ffi::glfwWaitEvents();
1589 }
1590 }
1591
1592 pub fn wait_events_unbuffered<F>(&mut self, mut f: F)
1597 where
1598 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1599 {
1600 let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1601 self.wait_events();
1602 }
1603
1604 pub fn wait_events_timeout(&mut self, timeout: f64) {
1610 unsafe {
1611 ffi::glfwWaitEventsTimeout(timeout);
1612 }
1613 }
1614
1615 pub fn wait_events_timeout_unbuffered<F>(&mut self, timeout: f64, mut f: F)
1621 where
1622 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>,
1623 {
1624 let _unset_handler_guard = unsafe { crate::callbacks::unbuffered::set_handler(&mut f) };
1625 self.wait_events_timeout(timeout);
1626 }
1627
1628 pub fn post_empty_event(&self) {
1634 unsafe {
1635 ffi::glfwPostEmptyEvent();
1636 }
1637 }
1638
1639 pub fn get_time(&self) -> f64 {
1645 unsafe { ffi::glfwGetTime() as f64 }
1646 }
1647
1648 pub fn set_time(&mut self, time: f64) {
1652 unsafe {
1653 ffi::glfwSetTime(time as c_double);
1654 }
1655 }
1656
1657 pub fn get_timer_value(&self) -> u64 {
1659 unsafe { ffi::glfwGetTimerValue() as u64 }
1660 }
1661
1662 pub fn get_timer_frequency(&self) -> u64 {
1664 unsafe { ffi::glfwGetTimerFrequency() as u64 }
1665 }
1666
1667 pub fn set_swap_interval(&mut self, interval: SwapInterval) {
1672 unsafe {
1673 ffi::glfwSwapInterval(match interval {
1674 SwapInterval::None => 0_i32,
1675 SwapInterval::Adaptive => -1_i32,
1676 SwapInterval::Sync(interval) => interval as c_int,
1677 })
1678 }
1679 }
1680
1681 pub fn extension_supported(&self, extension: &str) -> bool {
1686 unsafe {
1687 with_c_str(extension, |extension| {
1688 ffi::glfwExtensionSupported(extension) == ffi::GLFW_TRUE
1689 })
1690 }
1691 }
1692
1693 #[cfg(feature = "vulkan")]
1702 pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
1703 let mut len: c_uint = 0;
1704
1705 unsafe {
1706 let raw_extensions: *const *const c_char =
1707 ffi::glfwGetRequiredInstanceExtensions(&mut len as *mut c_uint);
1708
1709 if !raw_extensions.is_null() {
1710 return Some(
1711 slice::from_raw_parts(raw_extensions, len as usize)
1712 .iter()
1713 .map(|extensions| string_from_c_str(*extensions))
1714 .collect(),
1715 );
1716 }
1717 }
1718
1719 None
1720 }
1721
1722 pub fn get_proc_address_raw(&self, procname: &str) -> GLProc {
1727 debug_assert!(unsafe { ffi::glfwGetCurrentContext() } != std::ptr::null_mut());
1728 with_c_str(procname, |procname| unsafe {
1729 ffi::glfwGetProcAddress(procname)
1730 })
1731 }
1732
1733 #[cfg(feature = "vulkan")]
1746 pub fn get_instance_proc_address_raw(
1747 &self,
1748 instance: ffi::VkInstance,
1749 procname: &str,
1750 ) -> VkProc {
1751 with_c_str(procname, |procname| unsafe {
1752 ffi::glfwGetInstanceProcAddress(instance, procname)
1753 })
1754 }
1755
1756 #[cfg(feature = "vulkan")]
1761 pub fn get_physical_device_presentation_support_raw(
1762 &self,
1763 instance: ffi::VkInstance,
1764 device: ffi::VkPhysicalDevice,
1765 queue_family: u32,
1766 ) -> bool {
1767 ffi::GLFW_TRUE
1768 == unsafe {
1769 ffi::glfwGetPhysicalDevicePresentationSupport(
1770 instance,
1771 device,
1772 queue_family as c_uint,
1773 )
1774 }
1775 }
1776
1777 pub fn get_joystick(&self, id: JoystickId) -> Joystick {
1779 Joystick {
1780 id,
1781 glfw: self.clone(),
1782 }
1783 }
1784
1785 pub fn supports_raw_motion(&self) -> bool {
1787 unsafe { ffi::glfwRawMouseMotionSupported() == ffi::GLFW_TRUE }
1788 }
1789
1790 pub fn update_gamepad_mappings(&self, mappings: &str) -> bool {
1801 unsafe {
1802 with_c_str(mappings, |mappings| {
1803 ffi::glfwUpdateGamepadMappings(mappings) == ffi::GLFW_TRUE
1804 })
1805 }
1806 }
1807}
1808
1809impl Clone for Glfw {
1810 fn clone(&self) -> Self {
1811 REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
1812 Glfw {
1813 phantom: std::marker::PhantomData,
1814 }
1815 }
1816}
1817
1818impl Drop for Glfw {
1819 fn drop(&mut self) {
1820 let old_diff = REF_COUNT_FOR_GLFW.fetch_sub(1, Ordering::SeqCst);
1821 if old_diff == 1 {
1822 unsafe {
1823 ffi::glfwTerminate();
1824 }
1825 }
1826 }
1827}
1828
1829fn glfw_channel<T>(initial_capacity: usize, max_len: usize) -> (GlfwSender<T>, GlfwReceiver<T>) {
1830 let shared = Arc::new(SharedTransmitter {
1831 queue: Mutex::new(VecDeque::with_capacity(initial_capacity)),
1832 max_len,
1833 });
1834 let (mpsc_sender, mpsc_receiver) = channel();
1835
1836 let sender = GlfwSender {
1837 transmitter: shared.clone(),
1838 sender: mpsc_sender,
1839 };
1840 let receiver = GlfwReceiver {
1841 transmitter: shared.clone(),
1842 receiver: mpsc_receiver,
1843 };
1844 (sender, receiver)
1845}
1846
1847#[derive(Debug)]
1848struct SharedTransmitter<T> {
1849 queue: Mutex<VecDeque<T>>,
1850 max_len: usize,
1851}
1852
1853#[derive(Debug, Clone)]
1854struct GlfwSender<T> {
1855 transmitter: Arc<SharedTransmitter<T>>,
1856 sender: Sender<T>,
1857}
1858
1859impl<T> GlfwSender<T> {
1860 fn send(&self, v: T) {
1861 let mut queue = self.transmitter.queue.lock().unwrap();
1862 if queue.len() >= self.transmitter.max_len {
1863 let _ = self.sender.send(v);
1864 } else {
1865 queue.push_back(v);
1866 }
1867 }
1868}
1869
1870#[derive(Debug)]
1871pub struct GlfwReceiver<T> {
1872 transmitter: Arc<SharedTransmitter<T>>,
1873 receiver: Receiver<T>,
1874}
1875
1876impl<T> GlfwReceiver<T> {
1877 pub fn receive(&self) -> Option<T> {
1878 let ret = self.transmitter.queue.lock().unwrap().pop_front();
1879 if ret.is_some() {
1880 ret
1881 } else {
1882 match self.receiver.try_recv() {
1883 Ok(ret) => Some(ret),
1884 Err(_) => None,
1885 }
1886 }
1887 }
1888}
1889
1890struct WindowCallbacks {
1891 window_ptr: *mut Window,
1892 sender: GlfwSender<(f64, WindowEvent)>,
1893 pos_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1894 size_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1895 close_callback: Option<Box<dyn FnMut(&mut Window)>>,
1896 refresh_callback: Option<Box<dyn FnMut(&mut Window)>>,
1897 focus_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1898 iconify_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1899 framebuffer_size_callback: Option<Box<dyn FnMut(&mut Window, i32, i32)>>,
1900 key_callback: Option<Box<dyn FnMut(&mut Window, Key, Scancode, Action, Modifiers)>>,
1901 char_callback: Option<Box<dyn FnMut(&mut Window, char)>>,
1902 char_mods_callback: Option<Box<dyn FnMut(&mut Window, char, Modifiers)>>,
1903 mouse_button_callback: Option<Box<dyn FnMut(&mut Window, MouseButton, Action, Modifiers)>>,
1904 cursor_pos_callback: Option<Box<dyn FnMut(&mut Window, f64, f64)>>,
1905 cursor_enter_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1906 scroll_callback: Option<Box<dyn FnMut(&mut Window, f64, f64)>>,
1907 drag_and_drop_callback: Option<Box<dyn FnMut(&mut Window, Vec<PathBuf>)>>,
1908 maximize_callback: Option<Box<dyn FnMut(&mut Window, bool)>>,
1909 content_scale_callback: Option<Box<dyn FnMut(&mut Window, f32, f32)>>,
1910 pos_polling: bool,
1911 size_polling: bool,
1912 close_polling: bool,
1913 refresh_polling: bool,
1914 focus_polling: bool,
1915 iconify_polling: bool,
1916 framebuffer_size_polling: bool,
1917 key_polling: bool,
1918 char_polling: bool,
1919 char_mods_polling: bool,
1920 mouse_button_polling: bool,
1921 cursor_pos_polling: bool,
1922 cursor_enter_polling: bool,
1923 scroll_polling: bool,
1924 drag_and_drop_polling: bool,
1925 maximize_polling: bool,
1926 content_scale_polling: bool,
1927}
1928
1929impl WindowCallbacks {
1930 fn new(sender: GlfwSender<(f64, WindowEvent)>) -> Self {
1931 Self {
1932 window_ptr: std::ptr::null_mut(),
1933 sender,
1934 pos_callback: None,
1935 size_callback: None,
1936 close_callback: None,
1937 refresh_callback: None,
1938 focus_callback: None,
1939 iconify_callback: None,
1940 framebuffer_size_callback: None,
1941 key_callback: None,
1942 char_callback: None,
1943 char_mods_callback: None,
1944 mouse_button_callback: None,
1945 cursor_pos_callback: None,
1946 cursor_enter_callback: None,
1947 scroll_callback: None,
1948 drag_and_drop_callback: None,
1949 maximize_callback: None,
1950 content_scale_callback: None,
1951 pos_polling: false,
1952 size_polling: false,
1953 close_polling: false,
1954 refresh_polling: false,
1955 focus_polling: false,
1956 iconify_polling: false,
1957 framebuffer_size_polling: false,
1958 key_polling: false,
1959 char_polling: false,
1960 char_mods_polling: false,
1961 mouse_button_polling: false,
1962 cursor_pos_polling: false,
1963 cursor_enter_polling: false,
1964 scroll_polling: false,
1965 drag_and_drop_polling: false,
1966 maximize_polling: false,
1967 content_scale_polling: false,
1968 }
1969 }
1970
1971 fn get_callbacks<'a>(window: *mut GLFWwindow) -> &'a mut WindowCallbacks {
1972 unsafe { &mut *(ffi::glfwGetWindowUserPointer(window) as *mut WindowCallbacks) }
1973 }
1974}
1975
1976pub fn get_error() -> Error {
1978 unsafe { mem::transmute(ffi::glfwGetError(null_mut())) }
1979}
1980
1981pub fn get_error_string() -> (Error, String) {
1983 unsafe {
1984 let mut description: *const c_char = null();
1985 let error: Error = mem::transmute(ffi::glfwGetError(&mut description));
1986 (error, string_from_c_str(description))
1987 }
1988}
1989
1990pub fn get_version() -> Version {
1992 unsafe {
1993 let mut major = 0;
1994 let mut minor = 0;
1995 let mut patch = 0;
1996 ffi::glfwGetVersion(&mut major, &mut minor, &mut patch);
1997 Version {
1998 major: major as u64,
1999 minor: minor as u64,
2000 patch: patch as u64,
2001 }
2002 }
2003}
2004
2005pub unsafe fn string_from_c_str(c_str: *const c_char) -> String {
2007 String::from_utf8_lossy(CStr::from_ptr(c_str).to_bytes()).into_owned()
2008}
2009
2010pub unsafe fn string_from_nullable_c_str(c_str: *const c_char) -> Option<String> {
2012 if c_str.is_null() {
2013 None
2014 } else {
2015 Some(string_from_c_str(c_str))
2016 }
2017}
2018
2019pub fn with_c_str<F, T>(s: &str, f: F) -> T
2021where
2022 F: FnOnce(*const c_char) -> T,
2023{
2024 let c_str = CString::new(s.as_bytes());
2025 f(c_str.unwrap().as_bytes_with_nul().as_ptr() as *const _)
2026}
2027
2028pub fn get_version_string() -> String {
2030 unsafe { string_from_c_str(ffi::glfwGetVersionString()) }
2031}
2032
2033#[allow(missing_copy_implementations)]
2035pub struct Monitor {
2036 ptr: *mut ffi::GLFWmonitor,
2037}
2038
2039impl std::fmt::Debug for Monitor {
2040 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2041 write!(f, "Monitor({:p})", self.ptr)
2042 }
2043}
2044
2045impl Monitor {
2046 pub fn get_pos(&self) -> (i32, i32) {
2048 unsafe {
2049 let mut xpos = 0;
2050 let mut ypos = 0;
2051 ffi::glfwGetMonitorPos(self.ptr, &mut xpos, &mut ypos);
2052 (xpos as i32, ypos as i32)
2053 }
2054 }
2055
2056 pub fn get_physical_size(&self) -> (i32, i32) {
2058 unsafe {
2059 let mut width = 0;
2060 let mut height = 0;
2061 ffi::glfwGetMonitorPhysicalSize(self.ptr, &mut width, &mut height);
2062 (width as i32, height as i32)
2063 }
2064 }
2065
2066 pub fn get_name(&self) -> Option<String> {
2068 unsafe { string_from_nullable_c_str(ffi::glfwGetMonitorName(self.ptr)) }
2069 }
2070
2071 pub fn get_video_modes(&self) -> Vec<VidMode> {
2073 unsafe {
2074 let mut count = 0;
2075 let ptr = ffi::glfwGetVideoModes(self.ptr, &mut count);
2076 if ptr.is_null() {
2077 return Vec::new();
2078 }
2079 slice::from_raw_parts(ptr, count as usize)
2080 .iter()
2081 .map(VidMode::from_glfw_vid_mode)
2082 .collect()
2083 }
2084 }
2085
2086 pub fn get_video_mode(&self) -> Option<VidMode> {
2088 unsafe {
2089 let ptr = ffi::glfwGetVideoMode(self.ptr);
2092 if ptr.is_null() {
2093 None
2094 } else {
2095 Some(VidMode::from_glfw_vid_mode(&*ptr))
2096 }
2097 }
2098 }
2099
2100 pub fn set_gamma(&mut self, gamma: f32) {
2102 unsafe {
2103 ffi::glfwSetGamma(self.ptr, gamma as c_float);
2104 }
2105 }
2106
2107 pub fn get_gamma_ramp(&self) -> GammaRamp {
2109 unsafe {
2110 let llramp = *ffi::glfwGetGammaRamp(self.ptr);
2111 GammaRamp {
2112 red: slice::from_raw_parts(llramp.red as *const c_ushort, llramp.size as usize)
2113 .iter()
2114 .copied()
2115 .collect(),
2116 green: slice::from_raw_parts(llramp.green as *const c_ushort, llramp.size as usize)
2117 .iter()
2118 .copied()
2119 .collect(),
2120 blue: slice::from_raw_parts(llramp.blue as *const c_ushort, llramp.size as usize)
2121 .iter()
2122 .copied()
2123 .collect(),
2124 }
2125 }
2126 }
2127
2128 pub fn set_gamma_ramp(&mut self, ramp: &mut GammaRamp) {
2130 unsafe {
2131 ffi::glfwSetGammaRamp(
2132 self.ptr,
2133 &ffi::GLFWgammaramp {
2134 red: ramp.red.as_mut_ptr(),
2135 green: ramp.green.as_mut_ptr(),
2136 blue: ramp.blue.as_mut_ptr(),
2137 size: ramp.red.len() as u32,
2138 },
2139 );
2140 }
2141 }
2142
2143 pub fn get_content_scale(&self) -> (f32, f32) {
2145 unsafe {
2146 let mut xscale = 0.0_f32;
2147 let mut yscale = 0.0_f32;
2148 ffi::glfwGetMonitorContentScale(self.ptr, &mut xscale, &mut yscale);
2149 (xscale, yscale)
2150 }
2151 }
2152
2153 pub fn get_workarea(&self) -> (i32, i32, i32, i32) {
2155 unsafe {
2156 let mut xpos = 0;
2157 let mut ypos = 0;
2158 let mut width = 0;
2159 let mut height = 0;
2160 ffi::glfwGetMonitorWorkarea(self.ptr, &mut xpos, &mut ypos, &mut width, &mut height);
2161 (xpos, ypos, width, height)
2162 }
2163 }
2164}
2165
2166#[repr(i32)]
2168#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2169#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2170pub enum MonitorEvent {
2171 Connected = ffi::GLFW_CONNECTED,
2172 Disconnected = ffi::GLFW_DISCONNECTED,
2173}
2174
2175impl VidMode {
2176 fn from_glfw_vid_mode(mode: &ffi::GLFWvidmode) -> VidMode {
2177 VidMode {
2178 width: mode.width as u32,
2179 height: mode.height as u32,
2180 red_bits: mode.redBits as u32,
2181 green_bits: mode.greenBits as u32,
2182 blue_bits: mode.blueBits as u32,
2183 refresh_rate: mode.refreshRate as u32,
2184 }
2185 }
2186}
2187
2188impl fmt::Debug for VidMode {
2189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2199 write!(
2200 f,
2201 "{} x {}, {} = {} + {} + {}, {} Hz",
2202 self.width,
2203 self.height,
2204 self.red_bits + self.green_bits + self.blue_bits,
2205 self.red_bits,
2206 self.green_bits,
2207 self.blue_bits,
2208 self.refresh_rate
2209 )
2210 }
2211}
2212
2213#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2215#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2216pub enum WindowHint {
2217 MousePassthrough(bool),
2218 RedBits(Option<u32>),
2220 GreenBits(Option<u32>),
2222 BlueBits(Option<u32>),
2224 AlphaBits(Option<u32>),
2226 DepthBits(Option<u32>),
2228 StencilBits(Option<u32>),
2230 AccumRedBits(Option<u32>),
2232 AccumGreenBits(Option<u32>),
2234 AccumBlueBits(Option<u32>),
2236 AccumAlphaBits(Option<u32>),
2238 AuxBuffers(Option<u32>),
2240 Stereo(bool),
2242 Samples(Option<u32>),
2245 SRgbCapable(bool),
2247 RefreshRate(Option<u32>),
2252 ClientApi(ClientApiHint),
2254 ContextVersionMajor(u32),
2260 ContextVersionMinor(u32),
2266 ContextVersion(u32, u32),
2276 ContextRobustness(ContextRobustnessHint),
2278 OpenGlForwardCompat(bool),
2285 OpenGlDebugContext(bool),
2290 OpenGlProfile(OpenGlProfileHint),
2295 Resizable(bool),
2301 Visible(bool),
2305 Decorated(bool),
2310 AutoIconify(bool),
2315 Floating(bool),
2320 Focused(bool),
2324 Maximized(bool),
2328 ContextNoError(bool),
2331 ContextCreationApi(ContextCreationApi),
2333 ContextReleaseBehavior(ContextReleaseBehavior),
2335 DoubleBuffer(bool),
2342 CenterCursor(bool),
2346 TransparentFramebuffer(bool),
2351 FocusOnShow(bool),
2353 ScaleToMonitor(bool),
2358 CocoaRetinaFramebuffer(bool),
2362 CocoaFrameName(Option<String>),
2367 CocoaGraphicsSwitching(bool),
2381 X11ClassName(Option<String>),
2383 X11InstanceName(Option<String>),
2385}
2386
2387#[repr(i32)]
2389#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2390#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2391pub enum ClientApiHint {
2392 NoApi = ffi::GLFW_NO_API,
2393 OpenGl = ffi::GLFW_OPENGL_API,
2394 OpenGlEs = ffi::GLFW_OPENGL_ES_API,
2395}
2396
2397#[repr(i32)]
2399#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2400#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2401pub enum ContextRobustnessHint {
2402 NoRobustness = ffi::GLFW_NO_ROBUSTNESS,
2403 NoResetNotification = ffi::GLFW_NO_RESET_NOTIFICATION,
2404 LoseContextOnReset = ffi::GLFW_LOSE_CONTEXT_ON_RESET,
2405}
2406
2407#[repr(i32)]
2409#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2410#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2411pub enum OpenGlProfileHint {
2412 Any = ffi::GLFW_OPENGL_ANY_PROFILE,
2413 Core = ffi::GLFW_OPENGL_CORE_PROFILE,
2414 Compat = ffi::GLFW_OPENGL_COMPAT_PROFILE,
2415}
2416
2417#[derive(Copy, Clone, Debug)]
2419pub enum WindowMode<'a> {
2420 FullScreen(&'a Monitor),
2422
2423 Windowed,
2425}
2426
2427impl<'a> WindowMode<'a> {
2429 fn to_ptr(&self) -> *mut ffi::GLFWmonitor {
2432 match *self {
2433 WindowMode::FullScreen(monitor) => monitor.ptr,
2434 WindowMode::Windowed => ptr::null_mut(),
2435 }
2436 }
2437}
2438
2439bitflags! {
2440 #[doc = "Key modifiers (e.g., Shift, Control, Alt, Super)"]
2441 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2442 pub struct Modifiers: ::std::os::raw::c_int {
2443 const Shift = crate::ffi::GLFW_MOD_SHIFT;
2444 const Control = crate::ffi::GLFW_MOD_CONTROL;
2445 const Alt = crate::ffi::GLFW_MOD_ALT;
2446 const Super = crate::ffi::GLFW_MOD_SUPER;
2447 const CapsLock = crate::ffi::GLFW_MOD_CAPS_LOCK;
2448 const NumLock = crate::ffi::GLFW_MOD_NUM_LOCK;
2449 }
2450}
2451
2452pub type Scancode = c_int;
2454
2455#[derive(Clone, PartialEq, PartialOrd, Debug)]
2457#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2458pub enum WindowEvent {
2459 Pos(i32, i32),
2460 Size(i32, i32),
2461 Close,
2462 Refresh,
2463 Focus(bool),
2464 Iconify(bool),
2465 FramebufferSize(i32, i32),
2466 MouseButton(MouseButton, Action, Modifiers),
2467 CursorPos(f64, f64),
2468 CursorEnter(bool),
2469 Scroll(f64, f64),
2470 Key(Key, Scancode, Action, Modifiers),
2471 Char(char),
2472 CharModifiers(char, Modifiers),
2473 FileDrop(Vec<PathBuf>),
2474 Maximize(bool),
2475 ContentScale(f32, f32),
2476}
2477
2478pub fn flush_messages<Message: Send>(
2490 receiver: &GlfwReceiver<Message>,
2491) -> FlushedMessages<'_, Message> {
2492 FlushedMessages(receiver)
2493}
2494
2495#[derive(Debug)]
2498pub struct FlushedMessages<'a, Message: Send>(&'a GlfwReceiver<Message>);
2499
2500unsafe impl<'a, Message: 'a + Send> Send for FlushedMessages<'a, Message> {}
2501
2502impl<'a, Message: 'static + Send> Iterator for FlushedMessages<'a, Message> {
2503 type Item = Message;
2504
2505 fn next(&mut self) -> Option<Message> {
2506 let FlushedMessages(receiver) = *self;
2507 receiver.receive()
2508 }
2509}
2510
2511#[derive(Debug)]
2513pub struct Window {
2514 ptr: *mut ffi::GLFWwindow,
2515 pub is_shared: bool,
2516 drop_sender: Option<Sender<()>>,
2518 #[allow(unused)]
2522 drop_receiver: Receiver<()>,
2523 current_cursor: Option<Cursor>,
2526 pub glfw: Glfw,
2527}
2528
2529impl Window {
2530 pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
2536 if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
2537 self.make_current();
2538 }
2539
2540 self.glfw.get_proc_address_raw(procname)
2541 }
2542
2543 #[cfg(feature = "vulkan")]
2556 pub fn get_instance_proc_address(
2557 &mut self,
2558 instance: ffi::VkInstance,
2559 procname: &str,
2560 ) -> VkProc {
2561 self.glfw.get_instance_proc_address_raw(instance, procname)
2562 }
2563
2564 #[cfg(feature = "vulkan")]
2569 pub fn get_physical_device_presentation_support(
2570 &self,
2571 instance: ffi::VkInstance,
2572 device: ffi::VkPhysicalDevice,
2573 queue_family: u32,
2574 ) -> bool {
2575 self.glfw
2576 .get_physical_device_presentation_support_raw(instance, device, queue_family)
2577 }
2578
2579 #[cfg(feature = "vulkan")]
2581 pub unsafe fn create_window_surface(
2582 &self,
2583 instance: ffi::VkInstance,
2584 allocator: *const ffi::VkAllocationCallbacks,
2585 surface: *mut ffi::VkSurfaceKHR,
2586 ) -> ffi::VkResult {
2587 unsafe { ffi::glfwCreateWindowSurface(instance, self.ptr, allocator, surface) }
2588 }
2589
2590 pub fn create_shared(
2594 &self,
2595 width: u32,
2596 height: u32,
2597 title: &str,
2598 mode: WindowMode<'_>,
2599 ) -> Option<(PWindow, GlfwReceiver<(f64, WindowEvent)>)> {
2600 self.glfw
2601 .create_window_intern(width, height, title, mode, Some(self))
2602 }
2603
2604 pub fn close(self) {}
2607
2608 pub fn render_context(&mut self) -> PRenderContext {
2611 PRenderContext(Box::new(RenderContext {
2612 ptr: self.ptr,
2613 glfw: self.glfw.clone(),
2614 drop_sender: self.drop_sender.as_ref().unwrap().clone(),
2616 }))
2617 }
2618
2619 pub fn should_close(&self) -> bool {
2621 unsafe { ffi::glfwWindowShouldClose(self.ptr) == ffi::GLFW_TRUE }
2622 }
2623
2624 pub fn set_should_close(&mut self, value: bool) {
2626 unsafe { ffi::glfwSetWindowShouldClose(self.ptr, value as c_int) }
2627 }
2628
2629 pub fn set_title(&mut self, title: &str) {
2633 unsafe {
2634 with_c_str(title, |title| {
2635 ffi::glfwSetWindowTitle(self.ptr, title);
2636 });
2637 }
2638 }
2639
2640 pub fn get_pos(&self) -> (i32, i32) {
2642 unsafe {
2643 let mut xpos = 0;
2644 let mut ypos = 0;
2645 ffi::glfwGetWindowPos(self.ptr, &mut xpos, &mut ypos);
2646 (xpos as i32, ypos as i32)
2647 }
2648 }
2649
2650 pub fn set_pos(&mut self, xpos: i32, ypos: i32) {
2652 unsafe {
2653 ffi::glfwSetWindowPos(self.ptr, xpos as c_int, ypos as c_int);
2654 }
2655 }
2656
2657 pub fn get_size(&self) -> (i32, i32) {
2659 unsafe {
2660 let mut width = 0;
2661 let mut height = 0;
2662 ffi::glfwGetWindowSize(self.ptr, &mut width, &mut height);
2663 (width as i32, height as i32)
2664 }
2665 }
2666
2667 pub fn set_size(&mut self, width: i32, height: i32) {
2669 unsafe {
2670 ffi::glfwSetWindowSize(self.ptr, width as c_int, height as c_int);
2671 }
2672 }
2673
2674 pub fn get_frame_size(&self) -> (i32, i32, i32, i32) {
2678 let (mut left, mut top, mut right, mut bottom): (i32, i32, i32, i32) = (0, 0, 0, 0);
2679
2680 unsafe {
2681 ffi::glfwGetWindowFrameSize(
2682 self.ptr,
2683 &mut left as *mut c_int,
2684 &mut top as *mut c_int,
2685 &mut right as *mut c_int,
2686 &mut bottom as *mut c_int,
2687 );
2688 }
2689
2690 (left, top, right, bottom)
2691 }
2692
2693 pub fn get_framebuffer_size(&self) -> (i32, i32) {
2695 unsafe {
2696 let mut width = 0;
2697 let mut height = 0;
2698 ffi::glfwGetFramebufferSize(self.ptr, &mut width, &mut height);
2699 (width as i32, height as i32)
2700 }
2701 }
2702
2703 pub fn set_aspect_ratio(&mut self, numer: u32, denum: u32) {
2705 unsafe { ffi::glfwSetWindowAspectRatio(self.ptr, numer as c_int, denum as c_int) }
2706 }
2707
2708 pub fn set_size_limits(
2714 &mut self,
2715 minwidth: Option<u32>,
2716 minheight: Option<u32>,
2717 maxwidth: Option<u32>,
2718 maxheight: Option<u32>,
2719 ) {
2720 unsafe {
2721 ffi::glfwSetWindowSizeLimits(
2722 self.ptr,
2723 unwrap_dont_care(minwidth),
2724 unwrap_dont_care(minheight),
2725 unwrap_dont_care(maxwidth),
2726 unwrap_dont_care(maxheight),
2727 )
2728 }
2729 }
2730
2731 pub fn iconify(&mut self) {
2733 unsafe {
2734 ffi::glfwIconifyWindow(self.ptr);
2735 }
2736 }
2737
2738 pub fn restore(&mut self) {
2740 unsafe {
2741 ffi::glfwRestoreWindow(self.ptr);
2742 }
2743 }
2744
2745 pub fn maximize(&mut self) {
2747 unsafe { ffi::glfwMaximizeWindow(self.ptr) }
2748 }
2749
2750 pub fn show(&mut self) {
2752 unsafe {
2753 ffi::glfwShowWindow(self.ptr);
2754 }
2755 }
2756
2757 pub fn hide(&mut self) {
2759 unsafe {
2760 ffi::glfwHideWindow(self.ptr);
2761 }
2762 }
2763
2764 pub fn with_window_mode<T, F>(&self, f: F) -> T
2777 where
2778 F: FnOnce(WindowMode<'_>) -> T,
2779 {
2780 let ptr = unsafe { ffi::glfwGetWindowMonitor(self.ptr) };
2781 if ptr.is_null() {
2782 f(WindowMode::Windowed)
2783 } else {
2784 f(WindowMode::FullScreen(&Monitor { ptr }))
2785 }
2786 }
2787
2788 pub fn set_monitor(
2790 &mut self,
2791 mode: WindowMode<'_>,
2792 xpos: i32,
2793 ypos: i32,
2794 width: u32,
2795 height: u32,
2796 refresh_rate: Option<u32>,
2797 ) {
2798 let monitor_ptr = if let WindowMode::FullScreen(monitor) = mode {
2799 monitor.ptr
2800 } else {
2801 ptr::null_mut()
2802 };
2803
2804 unsafe {
2805 ffi::glfwSetWindowMonitor(
2806 self.ptr,
2807 monitor_ptr,
2808 xpos as c_int,
2809 ypos as c_int,
2810 width as c_int,
2811 height as c_int,
2812 unwrap_dont_care(refresh_rate),
2813 )
2814 }
2815 }
2816
2817 pub fn focus(&mut self) {
2822 unsafe { ffi::glfwFocusWindow(self.ptr) }
2823 }
2824
2825 pub fn is_focused(&self) -> bool {
2827 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_FOCUSED) == ffi::GLFW_TRUE }
2828 }
2829
2830 pub fn is_iconified(&self) -> bool {
2832 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_ICONIFIED) == ffi::GLFW_TRUE }
2833 }
2834
2835 pub fn is_maximized(&self) -> bool {
2837 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_MAXIMIZED) == ffi::GLFW_TRUE }
2838 }
2839
2840 pub fn get_client_api(&self) -> c_int {
2842 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CLIENT_API) }
2843 }
2844
2845 pub fn get_context_version(&self) -> Version {
2852 unsafe {
2853 Version {
2854 major: ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_VERSION_MAJOR) as u64,
2855 minor: ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_VERSION_MINOR) as u64,
2856 patch: ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_REVISION) as u64,
2857 }
2858 }
2859 }
2860
2861 pub fn get_context_robustness(&self) -> c_int {
2863 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_CONTEXT_ROBUSTNESS) }
2864 }
2865
2866 pub fn is_opengl_forward_compat(&self) -> bool {
2868 unsafe {
2869 ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_OPENGL_FORWARD_COMPAT) == ffi::GLFW_TRUE
2870 }
2871 }
2872
2873 pub fn is_opengl_debug_context(&self) -> bool {
2875 unsafe {
2876 ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_OPENGL_DEBUG_CONTEXT) == ffi::GLFW_TRUE
2877 }
2878 }
2879
2880 pub fn get_opengl_profile(&self) -> c_int {
2882 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_OPENGL_PROFILE) }
2883 }
2884
2885 pub fn is_resizable(&self) -> bool {
2887 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_RESIZABLE) == ffi::GLFW_TRUE }
2888 }
2889
2890 pub fn set_resizable(&mut self, resizable: bool) {
2892 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_RESIZABLE, resizable as c_int) }
2893 }
2894
2895 pub fn is_visible(&self) -> bool {
2897 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_VISIBLE) == ffi::GLFW_TRUE }
2898 }
2899
2900 pub fn is_decorated(&self) -> bool {
2902 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_DECORATED) == ffi::GLFW_TRUE }
2903 }
2904
2905 pub fn set_decorated(&mut self, decorated: bool) {
2907 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_DECORATED, decorated as c_int) }
2908 }
2909
2910 pub fn is_auto_iconify(&self) -> bool {
2912 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_AUTO_ICONIFY) == ffi::GLFW_TRUE }
2913 }
2914
2915 pub fn set_auto_iconify(&mut self, auto_iconify: bool) {
2917 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_AUTO_ICONIFY, auto_iconify as c_int) }
2918 }
2919
2920 pub fn is_floating(&self) -> bool {
2922 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_FLOATING) == ffi::GLFW_TRUE }
2923 }
2924
2925 pub fn set_floating(&mut self, floating: bool) {
2927 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_FLOATING, floating as c_int) }
2928 }
2929
2930 pub fn is_framebuffer_transparent(&self) -> bool {
2932 unsafe {
2933 ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_TRANSPARENT_FRAMEBUFFER) == ffi::GLFW_TRUE
2934 }
2935 }
2936
2937 pub fn is_mouse_passthrough(&self) -> bool {
2939 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_MOUSE_PASSTHROUGH) == ffi::GLFW_TRUE }
2940 }
2941
2942 pub fn set_mouse_passthrough(&mut self, passthrough: bool) {
2944 unsafe {
2945 ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_MOUSE_PASSTHROUGH, passthrough as c_int);
2946 }
2947 }
2948
2949 pub fn is_focus_on_show(&self) -> bool {
2951 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_FOCUS_ON_SHOW) == ffi::GLFW_TRUE }
2952 }
2953
2954 pub fn set_focus_on_show(&mut self, focus_on_show: bool) {
2956 unsafe {
2957 ffi::glfwSetWindowAttrib(self.ptr, ffi::GLFW_FOCUS_ON_SHOW, focus_on_show as c_int)
2958 }
2959 }
2960
2961 pub fn is_hovered(&self) -> bool {
2963 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::GLFW_HOVERED) == ffi::GLFW_TRUE }
2964 }
2965
2966 new_callback!(
2967 doc -> "Wrapper for `glfwSetWindowPosCallback`.",
2968 set -> set_pos_callback,
2969 unset -> unset_pos_callback,
2970 poll -> set_pos_polling,
2971 callback_field -> pos_callback,
2972 poll_field -> pos_polling,
2973 window_event -> Pos(i32, i32),
2974 glfw -> glfwSetWindowPosCallback(x: c_int, y: c_int),
2975 convert_args -> (x as i32, y as i32),
2976 secret -> _pos_callback
2977 );
2978
2979 new_callback!(
2980 doc -> "Wrapper for `glfwSetWindowSizeCallback`.",
2981 set -> set_size_callback,
2982 unset -> unset_size_callback,
2983 poll -> set_size_polling,
2984 callback_field -> size_callback,
2985 poll_field -> size_polling,
2986 window_event -> Size(i32, i32),
2987 glfw -> glfwSetWindowSizeCallback(width: c_int, height: c_int),
2988 convert_args -> (width as i32, height as i32),
2989 secret -> _size_callback
2990 );
2991
2992 new_callback!(
2993 doc -> "Wrapper for `glfwSetWindowCloseCallback`.",
2994 set -> set_close_callback,
2995 unset -> unset_close_callback,
2996 poll -> set_close_polling,
2997 callback_field -> close_callback,
2998 poll_field -> close_polling,
2999 window_event -> Close,
3000 glfw -> glfwSetWindowCloseCallback(),
3001 convert_args -> (),
3002 secret -> _close_callback
3003 );
3004
3005 new_callback!(
3006 doc -> "Wrapper for `glfwSetWindowRefreshCallback`.",
3007 set -> set_refresh_callback,
3008 unset -> unset_refresh_callback,
3009 poll -> set_refresh_polling,
3010 callback_field -> refresh_callback,
3011 poll_field -> refresh_polling,
3012 window_event -> Refresh,
3013 glfw -> glfwSetWindowRefreshCallback(),
3014 convert_args -> (),
3015 secret -> _refresh_callback
3016 );
3017
3018 new_callback!(
3019 doc -> "Wrapper for `glfwSetWindowFocusCallback`.",
3020 set -> set_focus_callback,
3021 unset -> unset_focus_callback,
3022 poll -> set_focus_polling,
3023 callback_field -> focus_callback,
3024 poll_field -> focus_polling,
3025 window_event -> Focus(bool),
3026 glfw -> glfwSetWindowFocusCallback(focused: c_int),
3027 convert_args -> (focused == ffi::GLFW_TRUE),
3028 secret -> _focus_callback
3029 );
3030
3031 new_callback!(
3032 doc -> "Wrapper for `glfwSetWindowIconifyCallback`.",
3033 set -> set_iconify_callback,
3034 unset -> unset_iconify_callback,
3035 poll -> set_iconify_polling,
3036 callback_field -> iconify_callback,
3037 poll_field -> iconify_polling,
3038 window_event -> Iconify(bool),
3039 glfw -> glfwSetWindowIconifyCallback(iconified: c_int),
3040 convert_args -> (iconified == ffi::GLFW_TRUE),
3041 secret -> _iconify_callback
3042 );
3043
3044 new_callback!(
3045 doc -> "Wrapper for `glfwSetFramebufferSizeCallback`.",
3046 set -> set_framebuffer_size_callback,
3047 unset -> unset_framebuffer_size_callback,
3048 poll -> set_framebuffer_size_polling,
3049 callback_field -> framebuffer_size_callback,
3050 poll_field -> framebuffer_size_polling,
3051 window_event -> FramebufferSize(i32, i32),
3052 glfw -> glfwSetFramebufferSizeCallback(width: c_int, height: c_int),
3053 convert_args -> (width as i32, height as i32),
3054 secret -> _framebuffer_size_callback
3055 );
3056
3057 new_callback!(
3058 doc -> "Wrapper for `glfwSetKeyCallback`.",
3059 set -> set_key_callback,
3060 unset -> unset_key_callback,
3061 poll -> set_key_polling,
3062 callback_field -> key_callback,
3063 poll_field -> key_polling,
3064 window_event -> Key(Key, Scancode, Action, Modifiers),
3065 glfw -> glfwSetKeyCallback(key: c_int, scancode: c_int, action: c_int, mods: c_int),
3066 convert_args -> (
3067 mem::transmute(key),
3068 scancode, mem::transmute(action),
3069 Modifiers::from_bits(mods).unwrap()
3070 ),
3071 secret -> _key_callback
3072 );
3073
3074 new_callback!(
3075 doc -> "Wrapper for `glfwSetCharCallback`.",
3076 set -> set_char_callback,
3077 unset -> unset_char_callback,
3078 poll -> set_char_polling,
3079 callback_field -> char_callback,
3080 poll_field -> char_polling,
3081 window_event -> Char(char),
3082 glfw -> glfwSetCharCallback(character: c_uint),
3083 convert_args -> (::std::char::from_u32(character).unwrap()),
3084 secret -> _char_callback
3085 );
3086
3087 new_callback!(
3088 doc -> "Wrapper for `glfwSetCharModsCallback`.",
3089 set -> set_char_mods_callback,
3090 unset -> unset_char_mods_callback,
3091 poll -> set_char_mods_polling,
3092 callback_field -> char_mods_callback,
3093 poll_field -> char_mods_polling,
3094 window_event -> CharModifiers(char, Modifiers),
3095 glfw -> glfwSetCharModsCallback(character: c_uint, mods: c_int),
3096 convert_args -> (
3097 ::std::char::from_u32(character).unwrap(),
3098 Modifiers::from_bits(mods).unwrap()
3099 ),
3100 secret -> _char_mods_callback
3101 );
3102
3103 new_callback!(
3104 doc -> "Wrapper for `glfwSetMouseButtonCallback`.",
3105 set -> set_mouse_button_callback,
3106 unset -> unset_mouse_button_callback,
3107 poll -> set_mouse_button_polling,
3108 callback_field -> mouse_button_callback,
3109 poll_field -> mouse_button_polling,
3110 window_event -> MouseButton(MouseButton, Action, Modifiers),
3111 glfw -> glfwSetMouseButtonCallback(button: c_int, action: c_int, mods: c_int),
3112 convert_args -> (
3113 mem::transmute(button),
3114 mem::transmute(action),
3115 Modifiers::from_bits(mods).unwrap()
3116 ),
3117 secret -> _mouse_button_callback
3118 );
3119
3120 new_callback!(
3121 doc -> "Wrapper for `glfwSetCursorPosCallback`.",
3122 set -> set_cursor_pos_callback,
3123 unset -> unset_cursor_pos_callback,
3124 poll -> set_cursor_pos_polling,
3125 callback_field -> cursor_pos_callback,
3126 poll_field -> cursor_pos_polling,
3127 window_event -> CursorPos(f64, f64),
3128 glfw -> glfwSetCursorPosCallback(x: c_double, y: c_double),
3129 convert_args -> (x as f64, y as f64),
3130 secret -> _cursor_pos_callback
3131 );
3132
3133 new_callback!(
3134 doc -> "Wrapper for `glfwSetCursorEnterCallback`.",
3135 set -> set_cursor_enter_callback,
3136 unset -> unset_cursor_enter_callback,
3137 poll -> set_cursor_enter_polling,
3138 callback_field -> cursor_enter_callback,
3139 poll_field -> cursor_enter_polling,
3140 window_event -> CursorEnter(bool),
3141 glfw -> glfwSetCursorEnterCallback(entered: c_int),
3142 convert_args -> (entered == ffi::GLFW_TRUE),
3143 secret -> _cursor_enter_callback
3144 );
3145
3146 new_callback!(
3147 doc -> "Wrapper for `glfwSetScrollCallback`.",
3148 set -> set_scroll_callback,
3149 unset -> unset_scroll_callback,
3150 poll -> set_scroll_polling,
3151 callback_field -> scroll_callback,
3152 poll_field -> scroll_polling,
3153 window_event -> Scroll(f64, f64),
3154 glfw -> glfwSetScrollCallback(x: c_double, y: c_double),
3155 convert_args -> (x as f64, y as f64),
3156 secret -> _scroll_callback
3157 );
3158
3159 new_callback!(
3160 doc -> "Wrapper for `glfwSetDropCallback`.",
3161 set -> set_drag_and_drop_callback,
3162 unset -> unset_drag_and_drop_callback,
3163 poll -> set_drag_and_drop_polling,
3164 callback_field -> drag_and_drop_callback,
3165 poll_field -> drag_and_drop_polling,
3166 window_event -> FileDrop(Vec<PathBuf>),
3167 glfw -> glfwSetDropCallback(num_paths: c_int, paths: *mut *const c_char),
3168 convert_args -> ({
3169 slice::from_raw_parts(paths, num_paths as usize)
3170 .iter()
3171 .map(|path| PathBuf::from(std::str::from_utf8({
3172 CStr::from_ptr(*path)
3173 .to_bytes()
3174 })
3175 .unwrap()
3176 .to_string()))
3177 .collect()
3178 }),
3179 secret -> _drag_and_drop_callback
3180 );
3181
3182 new_callback!(
3183 doc -> "Wrapper for `glfwSetWindowMaximizeCallback`.",
3184 set -> set_maximize_callback,
3185 unset -> unset_maximize_callback,
3186 poll -> set_maximize_polling,
3187 callback_field -> maximize_callback,
3188 poll_field -> maximize_polling,
3189 window_event -> Maximize(bool),
3190 glfw -> glfwSetWindowMaximizeCallback(maximized: c_int),
3191 convert_args -> (maximized == ffi::GLFW_TRUE),
3192 secret -> _maximize_callback
3193 );
3194
3195 new_callback!(
3196 doc -> "Wrapper for `glfwSetWindowContentScaleCallback`.",
3197 set -> set_content_scale_callback,
3198 unset -> unset_content_scale_callback,
3199 poll -> set_content_scale_polling,
3200 callback_field -> content_scale_callback,
3201 poll_field -> content_scale_polling,
3202 window_event -> ContentScale(f32, f32),
3203 glfw -> glfwSetWindowContentScaleCallback(xscale: c_float, yscale: c_float),
3204 convert_args -> (xscale as f32, yscale as f32),
3205 secret -> _content_scale_callback
3206 );
3207
3208 pub fn set_all_polling(&mut self, should_poll: bool) {
3210 self.set_pos_polling(should_poll);
3211 self.set_size_polling(should_poll);
3212 self.set_close_polling(should_poll);
3213 self.set_refresh_polling(should_poll);
3214 self.set_focus_polling(should_poll);
3215 self.set_iconify_polling(should_poll);
3216 self.set_framebuffer_size_polling(should_poll);
3217 self.set_key_polling(should_poll);
3218 self.set_char_polling(should_poll);
3219 self.set_char_mods_polling(should_poll);
3220 self.set_mouse_button_polling(should_poll);
3221 self.set_cursor_pos_polling(should_poll);
3222 self.set_cursor_enter_polling(should_poll);
3223 self.set_scroll_polling(should_poll);
3224 self.set_drag_and_drop_polling(should_poll);
3225 self.set_maximize_polling(should_poll);
3226 self.set_content_scale_polling(should_poll);
3227 }
3228
3229 pub fn get_cursor_mode(&self) -> CursorMode {
3231 unsafe { mem::transmute(ffi::glfwGetInputMode(self.ptr, ffi::GLFW_CURSOR)) }
3232 }
3233
3234 pub fn set_cursor_mode(&mut self, mode: CursorMode) {
3236 unsafe {
3237 ffi::glfwSetInputMode(self.ptr, ffi::GLFW_CURSOR, mode as c_int);
3238 }
3239 }
3240
3241 pub fn set_cursor(&mut self, cursor: Option<Cursor>) -> Option<Cursor> {
3248 let previous = mem::replace(&mut self.current_cursor, cursor);
3249
3250 unsafe {
3251 ffi::glfwSetCursor(
3252 self.ptr,
3253 match self.current_cursor {
3254 Some(ref cursor) => cursor.ptr,
3255 None => ptr::null_mut(),
3256 },
3257 )
3258 }
3259
3260 previous
3261 }
3262
3263 #[cfg(feature = "image")]
3280 pub fn set_icon(&mut self, images: Vec<image::RgbaImage>) {
3281 let image_data: Vec<(Vec<_>, u32, u32)> = images
3284 .into_iter()
3285 .map(|image| {
3286 let (width, height) = image.dimensions();
3287
3288 (image.into_vec(), width, height)
3289 })
3290 .collect();
3291
3292 let glfw_images: Vec<ffi::GLFWimage> = image_data
3293 .iter()
3294 .map(|data| ffi::GLFWimage {
3295 width: data.1 as c_int,
3296 height: data.2 as c_int,
3297 pixels: data.0.as_ptr() as _,
3298 })
3299 .collect();
3300
3301 unsafe {
3302 ffi::glfwSetWindowIcon(
3303 self.ptr,
3304 glfw_images.len() as c_int,
3305 glfw_images.as_ptr() as *const ffi::GLFWimage,
3306 )
3307 }
3308 }
3309
3310 pub fn set_icon_from_pixels(&mut self, images: Vec<PixelImage>) {
3313 let glfw_images: Vec<ffi::GLFWimage> = images
3314 .iter()
3315 .map(|image: &PixelImage| ffi::GLFWimage {
3316 width: image.width as c_int,
3317 height: image.height as c_int,
3318 pixels: image.pixels.as_ptr() as _,
3319 })
3320 .collect();
3321
3322 unsafe {
3323 ffi::glfwSetWindowIcon(
3324 self.ptr,
3325 glfw_images.len() as c_int,
3326 glfw_images.as_ptr() as *const ffi::GLFWimage,
3327 )
3328 }
3329 }
3330
3331 pub fn has_sticky_keys(&self) -> bool {
3333 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_STICKY_KEYS) == ffi::GLFW_TRUE }
3334 }
3335
3336 pub fn set_sticky_keys(&mut self, value: bool) {
3338 unsafe {
3339 ffi::glfwSetInputMode(self.ptr, ffi::GLFW_STICKY_KEYS, value as c_int);
3340 }
3341 }
3342
3343 pub fn has_sticky_mouse_buttons(&self) -> bool {
3345 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_STICKY_MOUSE_BUTTONS) == ffi::GLFW_TRUE }
3346 }
3347
3348 pub fn set_sticky_mouse_buttons(&mut self, value: bool) {
3350 unsafe {
3351 ffi::glfwSetInputMode(self.ptr, ffi::GLFW_STICKY_MOUSE_BUTTONS, value as c_int);
3352 }
3353 }
3354
3355 pub fn does_store_lock_key_mods(&self) -> bool {
3357 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_LOCK_KEY_MODS) == ffi::GLFW_TRUE }
3358 }
3359
3360 pub fn set_store_lock_key_mods(&mut self, value: bool) {
3362 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::GLFW_LOCK_KEY_MODS, value as c_int) }
3363 }
3364
3365 pub fn uses_raw_mouse_motion(&self) -> bool {
3367 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::GLFW_RAW_MOUSE_MOTION) == ffi::GLFW_TRUE }
3368 }
3369
3370 pub fn set_raw_mouse_motion(&mut self, value: bool) {
3372 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::GLFW_RAW_MOUSE_MOTION, value as c_int) }
3373 }
3374
3375 pub fn get_key(&self, key: Key) -> Action {
3377 unsafe { mem::transmute(ffi::glfwGetKey(self.ptr, key as c_int)) }
3378 }
3379
3380 pub fn get_mouse_button(&self, button: MouseButton) -> Action {
3382 unsafe { mem::transmute(ffi::glfwGetMouseButton(self.ptr, button as c_int)) }
3383 }
3384
3385 pub fn get_cursor_pos(&self) -> (f64, f64) {
3387 unsafe {
3388 let mut xpos = 0.0;
3389 let mut ypos = 0.0;
3390 ffi::glfwGetCursorPos(self.ptr, &mut xpos, &mut ypos);
3391 (xpos as f64, ypos as f64)
3392 }
3393 }
3394
3395 pub fn set_cursor_pos(&mut self, xpos: f64, ypos: f64) {
3397 unsafe {
3398 ffi::glfwSetCursorPos(self.ptr, xpos as c_double, ypos as c_double);
3399 }
3400 }
3401
3402 pub fn set_clipboard_string(&mut self, string: &str) {
3404 unsafe {
3405 with_c_str(string, |string| {
3406 ffi::glfwSetClipboardString(self.ptr, string);
3407 });
3408 }
3409 }
3410
3411 pub fn get_clipboard_string(&self) -> Option<String> {
3413 unsafe { string_from_nullable_c_str(ffi::glfwGetClipboardString(self.ptr)) }
3414 }
3415
3416 pub fn get_opacity(&self) -> f32 {
3418 unsafe { ffi::glfwGetWindowOpacity(self.ptr) }
3419 }
3420
3421 pub fn set_opacity(&mut self, opacity: f32) {
3423 unsafe { ffi::glfwSetWindowOpacity(self.ptr, opacity) }
3424 }
3425
3426 pub fn request_attention(&mut self) {
3428 unsafe { ffi::glfwRequestWindowAttention(self.ptr) }
3429 }
3430
3431 pub fn get_content_scale(&self) -> (f32, f32) {
3433 unsafe {
3434 let mut xscale = 0.0_f32;
3435 let mut yscale = 0.0_f32;
3436 ffi::glfwGetWindowContentScale(self.ptr, &mut xscale, &mut yscale);
3437 (xscale, yscale)
3438 }
3439 }
3440
3441 #[cfg(target_os = "windows")]
3443 pub fn get_win32_window(&self) -> *mut c_void {
3444 unsafe { ffi::glfwGetWin32Window(self.ptr) }
3445 }
3446
3447 #[cfg(target_os = "windows")]
3449 pub fn get_wgl_context(&self) -> *mut c_void {
3450 unsafe { ffi::glfwGetWGLContext(self.ptr) }
3451 }
3452
3453 #[cfg(target_os = "macos")]
3455 pub fn get_cocoa_window(&self) -> *mut c_void {
3456 unsafe { ffi::glfwGetCocoaWindow(self.ptr) }
3457 }
3458
3459 #[cfg(target_os = "macos")]
3461 pub fn get_nsgl_context(&self) -> *mut c_void {
3462 unsafe { ffi::glfwGetNSGLContext(self.ptr) }
3463 }
3464
3465 #[cfg(all(not(target_os = "windows"), not(target_os = "macos"), feature = "x11"))]
3467 pub fn get_x11_window(&self) -> usize {
3468 unsafe { ffi::glfwGetX11Window(self.ptr) }
3469 }
3470
3471 #[cfg(all(
3473 not(target_os = "windows"),
3474 not(target_os = "macos"),
3475 feature = "wayland"
3476 ))]
3477 pub fn get_wayland_window(&self) -> *mut c_void {
3478 unsafe { ffi::glfwGetWaylandWindow(self.ptr) }
3479 }
3480
3481 #[cfg(all(not(target_os = "windows"), not(target_os = "macos"), feature = "x11"))]
3483 pub fn get_glx_context(&self) -> usize {
3484 unsafe { ffi::glfwGetGLXContext(self.ptr) }
3485 }
3486}
3487
3488impl Drop for Window {
3489 fn drop(&mut self) {
3495 drop(self.drop_sender.take());
3496
3497 #[cfg(feature = "log")]
3499 if self.drop_receiver.try_recv() != Err(std::sync::mpsc::TryRecvError::Disconnected) {
3500 debug!("Attempted to drop a Window before the `RenderContext` was dropped.");
3501 debug!("Blocking until the `RenderContext` was dropped.");
3502 let _ = self.drop_receiver.recv();
3503 }
3504
3505 if !self.ptr.is_null() {
3506 unsafe {
3507 let _: Box<WindowCallbacks> =
3508 mem::transmute(ffi::glfwGetWindowUserPointer(self.ptr));
3509 }
3510 }
3511
3512 if !self.is_shared {
3513 unsafe {
3514 ffi::glfwDestroyWindow(self.ptr);
3515 }
3516 }
3517 }
3518}
3519
3520#[derive(Debug)]
3521#[repr(transparent)]
3522pub struct PRenderContext(Box<RenderContext>);
3523
3524impl Deref for PRenderContext {
3525 type Target = RenderContext;
3526 fn deref(&self) -> &Self::Target {
3527 self.0.deref()
3528 }
3529}
3530
3531impl DerefMut for PRenderContext {
3532 fn deref_mut(&mut self) -> &mut Self::Target {
3533 self.0.deref_mut()
3534 }
3535}
3536
3537unsafe impl Send for PRenderContext {}
3538unsafe impl Sync for PRenderContext {}
3539
3540#[cfg(feature = "raw-window-handle-v0-6")]
3541impl HasWindowHandle for PRenderContext {
3542 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3543 self.0.window_handle()
3544 }
3545}
3546
3547#[cfg(feature = "raw-window-handle-v0-6")]
3548impl HasDisplayHandle for PRenderContext {
3549 fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
3550 self.0.display_handle()
3551 }
3552}
3553
3554#[derive(Debug)]
3556pub struct RenderContext {
3557 ptr: *mut ffi::GLFWwindow,
3558 glfw: Glfw,
3559 #[allow(dead_code)]
3562 drop_sender: Sender<()>,
3563}
3564
3565impl RenderContext {
3566 pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
3568 if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
3569 self.make_current();
3570 }
3571
3572 self.glfw.get_proc_address_raw(procname)
3573 }
3574
3575 #[cfg(feature = "vulkan")]
3577 pub fn get_instance_proc_address(
3578 &mut self,
3579 instance: ffi::VkInstance,
3580 procname: &str,
3581 ) -> VkProc {
3582 self.glfw.get_instance_proc_address_raw(instance, procname)
3583 }
3584
3585 #[cfg(feature = "vulkan")]
3587 pub fn get_physical_device_presentation_support(
3588 &self,
3589 instance: ffi::VkInstance,
3590 device: ffi::VkPhysicalDevice,
3591 queue_family: u32,
3592 ) -> bool {
3593 self.glfw
3594 .get_physical_device_presentation_support_raw(instance, device, queue_family)
3595 }
3596
3597 #[cfg(feature = "vulkan")]
3599 pub unsafe fn create_window_surface(
3600 &self,
3601 instance: ffi::VkInstance,
3602 allocator: *const ffi::VkAllocationCallbacks,
3603 surface: *mut ffi::VkSurfaceKHR,
3604 ) -> ffi::VkResult {
3605 unsafe { ffi::glfwCreateWindowSurface(instance, self.ptr, allocator, surface) }
3606 }
3607}
3608
3609unsafe impl Send for RenderContext {}
3610
3611pub trait Context {
3613 fn window_ptr(&self) -> *mut ffi::GLFWwindow;
3615
3616 fn window_id(&self) -> WindowId {
3618 self.window_ptr() as WindowId
3619 }
3620
3621 fn swap_buffers(&mut self) {
3627 let ptr = self.window_ptr();
3628 unsafe {
3629 ffi::glfwSwapBuffers(ptr);
3630 }
3631 }
3632
3633 fn is_current(&self) -> bool {
3635 self.window_ptr() == unsafe { ffi::glfwGetCurrentContext() }
3636 }
3637
3638 fn make_current(&mut self) {
3640 let ptr = self.window_ptr();
3641 unsafe {
3642 ffi::glfwMakeContextCurrent(ptr);
3643 }
3644 }
3645
3646 fn should_close(&self) -> bool {
3648 let ptr = self.window_ptr();
3649 unsafe { ffi::glfwWindowShouldClose(ptr) == ffi::GLFW_TRUE }
3650 }
3651
3652 fn set_should_close(&mut self, value: bool) {
3654 let ptr = self.window_ptr();
3655 unsafe {
3656 ffi::glfwSetWindowShouldClose(ptr, value as c_int);
3657 }
3658 }
3659
3660 fn post_empty_event(&self) {
3662 unsafe { ffi::glfwPostEmptyEvent() }
3663 }
3664}
3665
3666impl Context for Window {
3667 fn window_ptr(&self) -> *mut ffi::GLFWwindow {
3668 self.ptr
3669 }
3670}
3671
3672impl Context for RenderContext {
3673 fn window_ptr(&self) -> *mut ffi::GLFWwindow {
3674 self.ptr
3675 }
3676}
3677
3678#[cfg(feature = "raw-window-handle-v0-6")]
3679impl HasWindowHandle for Window {
3680 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3681 Ok(unsafe { WindowHandle::borrow_raw(raw_window_handle(self)) })
3682 }
3683}
3684
3685#[cfg(feature = "raw-window-handle-v0-6")]
3686impl HasWindowHandle for RenderContext {
3687 fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
3688 Ok(unsafe { WindowHandle::borrow_raw(raw_window_handle(self)) })
3689 }
3690}
3691
3692#[cfg(feature = "raw-window-handle-v0-6")]
3693impl HasDisplayHandle for Window {
3694 fn display_handle(&'_ self) -> Result<DisplayHandle<'_>, HandleError> {
3695 Ok(unsafe { DisplayHandle::borrow_raw(raw_display_handle()) })
3696 }
3697}
3698
3699#[cfg(feature = "raw-window-handle-v0-6")]
3700impl HasDisplayHandle for RenderContext {
3701 fn display_handle(&'_ self) -> Result<DisplayHandle<'_>, HandleError> {
3702 Ok(unsafe { DisplayHandle::borrow_raw(raw_display_handle()) })
3703 }
3704}
3705
3706#[cfg(feature = "raw-window-handle-v0-5")]
3707unsafe impl HasRawWindowHandle for Window {
3708 fn raw_window_handle(&self) -> RawWindowHandle {
3709 raw_window_handle(self)
3710 }
3711}
3712
3713#[cfg(feature = "raw-window-handle-v0-5")]
3714unsafe impl HasRawWindowHandle for RenderContext {
3715 fn raw_window_handle(&self) -> RawWindowHandle {
3716 raw_window_handle(self)
3717 }
3718}
3719
3720#[cfg(feature = "raw-window-handle-v0-5")]
3721unsafe impl HasRawDisplayHandle for Window {
3722 fn raw_display_handle(&self) -> RawDisplayHandle {
3723 raw_display_handle()
3724 }
3725}
3726
3727#[cfg(feature = "raw-window-handle-v0-5")]
3728unsafe impl HasRawDisplayHandle for RenderContext {
3729 fn raw_display_handle(&self) -> RawDisplayHandle {
3730 raw_display_handle()
3731 }
3732}
3733
3734#[cfg(feature = "raw-window-handle-v0-6")]
3735fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
3736 #[cfg(target_family = "windows")]
3737 {
3738 use std::num::NonZeroIsize;
3739
3740 use raw_window_handle::Win32WindowHandle;
3741 let (hwnd, hinstance): (*mut std::ffi::c_void, *mut std::ffi::c_void) = unsafe {
3742 let hwnd = ffi::glfwGetWin32Window(context.window_ptr());
3743 let hinstance: *mut c_void =
3744 winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null()) as _;
3745 (hwnd, hinstance as _)
3746 };
3747 let mut handle = Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
3748 handle.hinstance = NonZeroIsize::new(hinstance as isize);
3749 RawWindowHandle::Win32(handle)
3750 }
3751 #[cfg(all(
3752 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3753 any(feature = "x11", feature = "wayland")
3754 ))]
3755 {
3756 let platform = unsafe { mem::transmute::<i32, Platform>(ffi::glfwGetPlatform()) };
3757 match platform {
3758 #[cfg(feature = "x11")]
3759 Platform::X11 => {
3760 use raw_window_handle::XlibWindowHandle;
3761 let window = unsafe {
3762 ffi::glfwGetX11Window(context.window_ptr()) as std::os::raw::c_ulong
3763 };
3764 RawWindowHandle::Xlib(XlibWindowHandle::new(window))
3765 }
3766 #[cfg(feature = "wayland")]
3767 Platform::Wayland => {
3768 use std::ptr::NonNull;
3769 use raw_window_handle::WaylandWindowHandle;
3770 let surface = unsafe { ffi::glfwGetWaylandWindow(context.window_ptr()) };
3771 let handle = WaylandWindowHandle::new(
3772 NonNull::new(surface).expect("wayland window surface is null"),
3773 );
3774 RawWindowHandle::Wayland(handle)
3775 }
3776 _ => panic!("Unsupported platform: {:?}", platform),
3777 }
3778 }
3779 #[cfg(target_os = "macos")]
3780 {
3781 use std::ptr::NonNull;
3782
3783 use objc2::msg_send_id;
3784 use objc2::rc::Id;
3785 use objc2::runtime::NSObject;
3786 use raw_window_handle::AppKitWindowHandle;
3787 let ns_window: *mut NSObject =
3788 unsafe { ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _ };
3789 let ns_view: Option<Id<NSObject>> = unsafe { msg_send_id![ns_window, contentView] };
3790 let ns_view = ns_view.expect("failed to access contentView on GLFW NSWindow");
3791 let ns_view: NonNull<NSObject> = NonNull::from(&*ns_view);
3792 let handle = AppKitWindowHandle::new(ns_view.cast());
3793 RawWindowHandle::AppKit(handle)
3794 }
3795 #[cfg(target_os = "emscripten")]
3796 {
3797 let _ = context; let mut wh = raw_window_handle::WebWindowHandle::new(1);
3799 RawWindowHandle::Web(wh)
3803 }
3804}
3805
3806#[cfg(feature = "raw-window-handle-v0-6")]
3807fn raw_display_handle() -> RawDisplayHandle {
3808 #[cfg(target_family = "windows")]
3809 {
3810 use raw_window_handle::WindowsDisplayHandle;
3811 RawDisplayHandle::Windows(WindowsDisplayHandle::new())
3812 }
3813 #[cfg(all(
3814 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3815 any(feature = "x11", feature = "wayland")
3816 ))]
3817 {
3818 let platform = unsafe { mem::transmute::<i32, Platform>(ffi::glfwGetPlatform()) };
3819 match platform {
3820 #[cfg(feature = "x11")]
3821 Platform::X11 => {
3822 use std::ptr::NonNull;
3823 use raw_window_handle::XlibDisplayHandle;
3824 let display = NonNull::new(unsafe { ffi::glfwGetX11Display() });
3825 let handle = XlibDisplayHandle::new(display, 0);
3826 RawDisplayHandle::Xlib(handle)
3827 }
3828 #[cfg(feature = "wayland")]
3829 Platform::Wayland => {
3830 use std::ptr::NonNull;
3831 use raw_window_handle::WaylandDisplayHandle;
3832 let display = NonNull::new(unsafe { ffi::glfwGetWaylandDisplay().cast_mut() })
3833 .expect("wayland display is null");
3834 let handle = WaylandDisplayHandle::new(display);
3835 RawDisplayHandle::Wayland(handle)
3836 }
3837 _ => panic!("Unsupported platform: {:?}", platform),
3838 }
3839 }
3840 #[cfg(target_os = "macos")]
3841 {
3842 use raw_window_handle::AppKitDisplayHandle;
3843 RawDisplayHandle::AppKit(AppKitDisplayHandle::new())
3844 }
3845 #[cfg(target_os = "emscripten")]
3846 {
3847 RawDisplayHandle::Web(raw_window_handle::WebDisplayHandle::new())
3848 }
3849}
3850
3851#[cfg(feature = "raw-window-handle-v0-5")]
3852fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
3853 #[cfg(target_family = "windows")]
3854 {
3855 use raw_window_handle::Win32WindowHandle;
3856 let (hwnd, hinstance) = unsafe {
3857 let hwnd = ffi::glfwGetWin32Window(context.window_ptr());
3858 let hinstance = winapi::um::libloaderapi::GetModuleHandleW(std::ptr::null());
3859 (hwnd, hinstance as _)
3860 };
3861 let mut handle = Win32WindowHandle::empty();
3862 handle.hwnd = hwnd;
3863 handle.hinstance = hinstance;
3864 RawWindowHandle::Win32(handle)
3865 }
3866 #[cfg(all(
3867 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3868 any(feature = "x11", feature = "wayland")
3869 ))]
3870 {
3871 let platform = unsafe { mem::transmute::<i32, Platform>(ffi::glfwGetPlatform()) };
3872 match platform {
3873 #[cfg(feature = "x11")]
3874 Platform::X11 => {
3875 use raw_window_handle::XlibWindowHandle;
3876 let mut handle = XlibWindowHandle::empty();
3877 handle.window = unsafe {
3878 ffi::glfwGetX11Window(context.window_ptr()) as std::os::raw::c_ulong
3879 };
3880 RawWindowHandle::Xlib(handle)
3881 }
3882 #[cfg(feature = "wayland")]
3883 Platform::Wayland => {
3884 use raw_window_handle::WaylandWindowHandle;
3885 let mut handle = WaylandWindowHandle::empty();
3886 handle.surface = unsafe { ffi::glfwGetWaylandWindow(context.window_ptr()) };
3887 RawWindowHandle::Wayland(handle)
3888 }
3889 _ => panic!("Unsupported platform: {:?}", platform),
3890 }
3891 }
3892 #[cfg(target_os = "macos")]
3893 {
3894 use raw_window_handle::AppKitWindowHandle;
3895 let (ns_window, ns_view) = unsafe {
3896 let ns_window: *mut objc::runtime::Object =
3897 ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _;
3898 let ns_view: *mut objc::runtime::Object = objc::msg_send![ns_window, contentView];
3899 assert_ne!(ns_view, std::ptr::null_mut());
3900 (
3901 ns_window as *mut std::ffi::c_void,
3902 ns_view as *mut std::ffi::c_void,
3903 )
3904 };
3905 let mut handle = AppKitWindowHandle::empty();
3906 handle.ns_window = ns_window;
3907 handle.ns_view = ns_view;
3908 RawWindowHandle::AppKit(handle)
3909 }
3910 #[cfg(target_os = "emscripten")]
3911 {
3912 let _ = context; let mut wh = raw_window_handle::WebWindowHandle::empty();
3914 wh.id = 1;
3918 RawWindowHandle::Web(wh)
3919 }
3920}
3921
3922#[cfg(feature = "raw-window-handle-v0-5")]
3923fn raw_display_handle() -> RawDisplayHandle {
3924 #[cfg(target_family = "windows")]
3925 {
3926 use raw_window_handle::WindowsDisplayHandle;
3927 RawDisplayHandle::Windows(WindowsDisplayHandle::empty())
3928 }
3929 #[cfg(all(
3930 any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly"),
3931 any(feature = "x11", feature = "wayland")
3932 ))]
3933 {
3934 let platform = unsafe { mem::transmute::<i32, Platform>(ffi::glfwGetPlatform()) };
3935 match platform {
3936 #[cfg(feature = "x11")]
3937 Platform::X11 => {
3938 use raw_window_handle::XlibDisplayHandle;
3939 let mut handle = XlibDisplayHandle::empty();
3940 handle.display = unsafe { ffi::glfwGetX11Display() };
3941 RawDisplayHandle::Xlib(handle)
3942 }
3943 #[cfg(feature = "wayland")]
3944 Platform::Wayland => {
3945 use raw_window_handle::WaylandDisplayHandle;
3946 let mut handle = WaylandDisplayHandle::empty();
3947 handle.display = unsafe { ffi::glfwGetWaylandDisplay().cast_mut() };
3949 RawDisplayHandle::Wayland(handle)
3950 }
3951 _ => panic!("Unsupported platform: {:?}", platform),
3952 }
3953 }
3954 #[cfg(target_os = "macos")]
3955 {
3956 use raw_window_handle::AppKitDisplayHandle;
3957 RawDisplayHandle::AppKit(AppKitDisplayHandle::empty())
3958 }
3959 #[cfg(target_os = "emscripten")]
3960 {
3961 RawDisplayHandle::Web(raw_window_handle::WebDisplayHandle::empty())
3962 }
3963}
3964
3965pub fn make_context_current(context: Option<&dyn Context>) {
3967 match context {
3968 Some(ctx) => unsafe { ffi::glfwMakeContextCurrent(ctx.window_ptr()) },
3969 None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
3970 }
3971}
3972
3973#[repr(i32)]
3975#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
3976#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3977pub enum JoystickId {
3978 Joystick1 = ffi::GLFW_JOYSTICK_1,
3979 Joystick2 = ffi::GLFW_JOYSTICK_2,
3980 Joystick3 = ffi::GLFW_JOYSTICK_3,
3981 Joystick4 = ffi::GLFW_JOYSTICK_4,
3982 Joystick5 = ffi::GLFW_JOYSTICK_5,
3983 Joystick6 = ffi::GLFW_JOYSTICK_6,
3984 Joystick7 = ffi::GLFW_JOYSTICK_7,
3985 Joystick8 = ffi::GLFW_JOYSTICK_8,
3986 Joystick9 = ffi::GLFW_JOYSTICK_9,
3987 Joystick10 = ffi::GLFW_JOYSTICK_10,
3988 Joystick11 = ffi::GLFW_JOYSTICK_11,
3989 Joystick12 = ffi::GLFW_JOYSTICK_12,
3990 Joystick13 = ffi::GLFW_JOYSTICK_13,
3991 Joystick14 = ffi::GLFW_JOYSTICK_14,
3992 Joystick15 = ffi::GLFW_JOYSTICK_15,
3993 Joystick16 = ffi::GLFW_JOYSTICK_16,
3994}
3995
3996impl JoystickId {
3997 pub fn from_i32(n: i32) -> Option<JoystickId> {
3999 if (0..=ffi::GLFW_JOYSTICK_LAST).contains(&n) {
4000 Some(unsafe { mem::transmute(n) })
4001 } else {
4002 None
4003 }
4004 }
4005}
4006
4007#[repr(i32)]
4009#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
4010#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4011pub enum GamepadButton {
4012 ButtonA = ffi::GLFW_GAMEPAD_BUTTON_A,
4013 ButtonB = ffi::GLFW_GAMEPAD_BUTTON_B,
4014 ButtonX = ffi::GLFW_GAMEPAD_BUTTON_X,
4015 ButtonY = ffi::GLFW_GAMEPAD_BUTTON_Y,
4016 ButtonLeftBumper = ffi::GLFW_GAMEPAD_BUTTON_LEFT_BUMPER,
4017 ButtonRightBumper = ffi::GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER,
4018 ButtonBack = ffi::GLFW_GAMEPAD_BUTTON_BACK,
4019 ButtonStart = ffi::GLFW_GAMEPAD_BUTTON_START,
4020 ButtonGuide = ffi::GLFW_GAMEPAD_BUTTON_GUIDE,
4021 ButtonLeftThumb = ffi::GLFW_GAMEPAD_BUTTON_LEFT_THUMB,
4022 ButtonRightThumb = ffi::GLFW_GAMEPAD_BUTTON_RIGHT_THUMB,
4023 ButtonDpadUp = ffi::GLFW_GAMEPAD_BUTTON_DPAD_UP,
4024 ButtonDpadRight = ffi::GLFW_GAMEPAD_BUTTON_DPAD_RIGHT,
4025 ButtonDpadDown = ffi::GLFW_GAMEPAD_BUTTON_DPAD_DOWN,
4026 ButtonDpadLeft = ffi::GLFW_GAMEPAD_BUTTON_DPAD_LEFT,
4027}
4028
4029impl GamepadButton {
4030 pub fn from_i32(n: i32) -> Option<GamepadButton> {
4032 if (0..=ffi::GLFW_GAMEPAD_BUTTON_LAST).contains(&n) {
4033 Some(unsafe { mem::transmute(n) })
4034 } else {
4035 None
4036 }
4037 }
4038}
4039
4040#[repr(i32)]
4042#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
4043#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4044pub enum GamepadAxis {
4045 AxisLeftX = ffi::GLFW_GAMEPAD_AXIS_LEFT_X,
4046 AxisLeftY = ffi::GLFW_GAMEPAD_AXIS_LEFT_Y,
4047 AxisRightX = ffi::GLFW_GAMEPAD_AXIS_RIGHT_X,
4048 AxisRightY = ffi::GLFW_GAMEPAD_AXIS_RIGHT_Y,
4049 AxisLeftTrigger = ffi::GLFW_GAMEPAD_AXIS_LEFT_TRIGGER,
4050 AxisRightTrigger = ffi::GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER,
4051}
4052
4053impl GamepadAxis {
4054 pub fn from_i32(n: i32) -> Option<GamepadAxis> {
4056 if (0..=ffi::GLFW_GAMEPAD_AXIS_LAST).contains(&n) {
4057 Some(unsafe { mem::transmute(n) })
4058 } else {
4059 None
4060 }
4061 }
4062}
4063
4064bitflags! {
4065 #[doc = "Joystick hats."]
4066 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4067 pub struct JoystickHats: ::std::os::raw::c_int {
4068 const Centered = crate::ffi::GLFW_HAT_CENTERED;
4069 const Up = crate::ffi::GLFW_HAT_UP;
4070 const Right = crate::ffi::GLFW_HAT_RIGHT;
4071 const Down = crate::ffi::GLFW_HAT_DOWN;
4072 const Left = crate::ffi::GLFW_HAT_LEFT;
4073 }
4074}
4075
4076#[derive(Clone, Debug)]
4078pub struct Joystick {
4079 pub id: JoystickId,
4080 pub glfw: Glfw,
4081}
4082
4083#[derive(Copy, Clone, Debug)]
4085#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4086pub struct GamepadState {
4087 buttons: [Action; (ffi::GLFW_GAMEPAD_BUTTON_LAST + 1) as usize],
4088 axes: [f32; (ffi::GLFW_GAMEPAD_AXIS_LAST + 1) as usize],
4089}
4090
4091#[repr(i32)]
4093#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
4094#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4095pub enum JoystickEvent {
4096 Connected = ffi::GLFW_CONNECTED,
4097 Disconnected = ffi::GLFW_DISCONNECTED,
4098}
4099
4100impl Joystick {
4101 pub fn is_present(&self) -> bool {
4103 unsafe { ffi::glfwJoystickPresent(self.id as c_int) == ffi::GLFW_TRUE }
4104 }
4105
4106 pub fn get_axes(&self) -> Vec<f32> {
4108 unsafe {
4109 let mut count = 0;
4110 let ptr = ffi::glfwGetJoystickAxes(self.id as c_int, &mut count);
4111 if ptr.is_null() {
4112 return Vec::new();
4113 }
4114 slice::from_raw_parts(ptr, count as usize)
4115 .iter()
4116 .map(|&a| a as f32)
4117 .collect()
4118 }
4119 }
4120
4121 pub fn get_buttons(&self) -> Vec<c_int> {
4123 unsafe {
4124 let mut count = 0;
4125 let ptr = ffi::glfwGetJoystickButtons(self.id as c_int, &mut count);
4126 if ptr.is_null() {
4127 return Vec::new();
4128 }
4129 slice::from_raw_parts(ptr, count as usize)
4130 .iter()
4131 .map(|&b| b as c_int)
4132 .collect()
4133 }
4134 }
4135
4136 pub fn get_hats(&self) -> Vec<JoystickHats> {
4138 unsafe {
4139 let mut count = 0;
4140 let ptr = ffi::glfwGetJoystickHats(self.id as c_int, &mut count);
4141 if ptr.is_null() {
4142 return Vec::new();
4143 }
4144 slice::from_raw_parts(ptr, count as usize)
4145 .iter()
4146 .map(|&b| mem::transmute(b as c_int))
4147 .collect()
4148 }
4149 }
4150
4151 pub fn get_name(&self) -> Option<String> {
4153 unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickName(self.id as c_int)) }
4154 }
4155
4156 pub fn get_guid(&self) -> Option<String> {
4158 unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickGUID(self.id as c_int)) }
4159 }
4160
4161 pub fn is_gamepad(&self) -> bool {
4163 unsafe { ffi::glfwJoystickIsGamepad(self.id as c_int) == ffi::GLFW_TRUE }
4164 }
4165
4166 pub fn get_gamepad_name(&self) -> Option<String> {
4168 unsafe { string_from_nullable_c_str(ffi::glfwGetGamepadName(self.id as c_int)) }
4169 }
4170
4171 pub fn get_gamepad_state(&self) -> Option<GamepadState> {
4173 unsafe {
4174 let mut state = ffi::GLFWgamepadstate {
4175 buttons: [0; (ffi::GLFW_GAMEPAD_BUTTON_LAST + 1) as usize],
4176 axes: [0_f32; (ffi::GLFW_GAMEPAD_AXIS_LAST + 1) as usize],
4177 };
4178 if ffi::glfwGetGamepadState(self.id as c_int, &mut state) == ffi::GLFW_TRUE {
4179 Some(state.into())
4180 } else {
4181 None
4182 }
4183 }
4184 }
4185}
4186
4187impl From<ffi::GLFWgamepadstate> for GamepadState {
4188 fn from(state: ffi::GLFWgamepadstate) -> Self {
4189 let mut buttons = [Action::Release; (ffi::GLFW_GAMEPAD_BUTTON_LAST + 1) as usize];
4190 let mut axes = [0_f32; (ffi::GLFW_GAMEPAD_AXIS_LAST + 1) as usize];
4191 unsafe {
4192 state
4193 .buttons
4194 .iter()
4195 .map(|&b| mem::transmute(b as c_int))
4196 .zip(buttons.iter_mut())
4197 .for_each(|(a, b)| *b = a);
4198 }
4199 state
4200 .axes
4201 .iter()
4202 .map(|&f| f as f32)
4203 .zip(axes.iter_mut())
4204 .for_each(|(a, b)| *b = a);
4205 Self { buttons, axes }
4206 }
4207}
4208
4209impl GamepadState {
4210 pub fn get_button_state(&self, button: GamepadButton) -> Action {
4211 self.buttons[button as usize]
4212 }
4213
4214 pub fn get_axis(&self, axis: GamepadAxis) -> f32 {
4215 self.axes[axis as usize]
4216 }
4217}
4218
4219#[inline(always)]
4220fn unwrap_dont_care(value: Option<u32>) -> c_int {
4221 match value {
4222 Some(v) => v as c_int,
4223 None => ffi::GLFW_DONT_CARE,
4224 }
4225}