1 // Copyright 2013-2016 The GLFW-RS Developers. For a full listing of the authors,
2 // refer to the AUTHORS file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #![crate_type = "lib"]
17 #![crate_type = "rlib"]
18 #![crate_type = "dylib"]
19 #![crate_name = "glfw"]
20
21 #![allow(non_upper_case_globals)]
22
23 //! An idiomatic wrapper for the GLFW library.
24 //!
25 //! # Example
26 //!
27 //! ~~~no_run
28 //! extern crate glfw;
29 //!
30 //! use glfw::{Action, Context, Key};
31 //!
32 //! fn main() {
33 //! let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
34 //!
35 //! // Create a windowed mode window and its OpenGL context
36 //! let (mut window, events) = glfw.create_window(300, 300, "Hello this is window", glfw::WindowMode::Windowed)
37 //! .expect("Failed to create GLFW window.");
38 //!
39 //! // Make the window's context current
40 //! window.make_current();
41 //! window.set_key_polling(true);
42 //!
43 //! // Loop until the user closes the window
44 //! while !window.should_close() {
45 //! // Swap front and back buffers
46 //! window.swap_buffers();
47 //!
48 //! // Poll for and process events
49 //! glfw.poll_events();
50 //! for (_, event) in glfw::flush_messages(&events) {
51 //! println!("{:?}", event);
52 //! match event {
53 //! glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
54 //! window.set_should_close(true)
55 //! },
56 //! _ => {},
57 //! }
58 //! }
59 //! }
60 //! }
61 //! ~~~
62 //!
63 //! # Cargo Features
64 //!
65 //! Use the `vulkan` feature flag to enable all Vulkan functions and types.
66 //!
67 //! Use the `image` feature flag to enable use of the [`image`](https://github.com/PistonDevelopers/image) library for cursors and icons.
68 //!
69 //! Use the `all` feature flag to enable both at the same time.
70 //!
71
72 // TODO: Document differences between GLFW and glfw-rs
73
74 extern crate semver;
75 extern crate libc;
76 #[cfg(feature = "vulkan")]
77 extern crate vk_sys;
78 #[macro_use]
79 extern crate log;
80 #[macro_use]
81 extern crate bitflags;
82 #[cfg(feature = "image")]
83 extern crate image;
84 extern crate raw_window_handle;
85 #[cfg(all(target_os="macos"))]
86 #[macro_use]
87 extern crate objc;
88
89 use libc::{c_char, c_double, c_float, c_int};
90 use libc::{c_ushort, c_void, c_uchar};
91 #[cfg(feature = "vulkan")]
92 use libc::c_uint;
93 use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
94 use std::ffi::{CStr, CString};
95 use std::mem;
96 use std::sync::mpsc::{channel, Receiver, Sender};
97 use std::fmt;
98 use std::error;
99 use std::marker::Send;
100 use std::ptr;
101 use std::slice;
102 use std::path::PathBuf;
103 use std::sync::atomic::{AtomicUsize, Ordering};
104 use semver::Version;
105
106 #[cfg(feature = "vulkan")]
107 use vk_sys::{
108 self as vk,
109 Instance as VkInstance,
110 PhysicalDevice as VkPhysicalDevice
111 };
112
113 /// Alias to `MouseButton1`, supplied for improved clarity.
114 pub use self::MouseButton::Button1 as MouseButtonLeft;
115 /// Alias to `MouseButton2`, supplied for improved clarity.
116 pub use self::MouseButton::Button2 as MouseButtonRight;
117 /// Alias to `MouseButton3`, supplied for improved clarity.
118 pub use self::MouseButton::Button3 as MouseButtonMiddle;
119
120 pub mod ffi;
121 mod callbacks;
122
123 /// Unique identifier for a `Window`.
124 pub type WindowId = usize;
125
126 /// Input actions.
127 #[repr(i32)]
128 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
129 pub enum Action {
130 Release = ffi::RELEASE,
131 Press = ffi::PRESS,
132 Repeat = ffi::REPEAT,
133 }
134
135 /// Input keys.
136 #[repr(i32)]
137 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
138 pub enum Key {
139 Space = ffi::KEY_SPACE,
140 Apostrophe = ffi::KEY_APOSTROPHE,
141 Comma = ffi::KEY_COMMA,
142 Minus = ffi::KEY_MINUS,
143 Period = ffi::KEY_PERIOD,
144 Slash = ffi::KEY_SLASH,
145 Num0 = ffi::KEY_0,
146 Num1 = ffi::KEY_1,
147 Num2 = ffi::KEY_2,
148 Num3 = ffi::KEY_3,
149 Num4 = ffi::KEY_4,
150 Num5 = ffi::KEY_5,
151 Num6 = ffi::KEY_6,
152 Num7 = ffi::KEY_7,
153 Num8 = ffi::KEY_8,
154 Num9 = ffi::KEY_9,
155 Semicolon = ffi::KEY_SEMICOLON,
156 Equal = ffi::KEY_EQUAL,
157 A = ffi::KEY_A,
158 B = ffi::KEY_B,
159 C = ffi::KEY_C,
160 D = ffi::KEY_D,
161 E = ffi::KEY_E,
162 F = ffi::KEY_F,
163 G = ffi::KEY_G,
164 H = ffi::KEY_H,
165 I = ffi::KEY_I,
166 J = ffi::KEY_J,
167 K = ffi::KEY_K,
168 L = ffi::KEY_L,
169 M = ffi::KEY_M,
170 N = ffi::KEY_N,
171 O = ffi::KEY_O,
172 P = ffi::KEY_P,
173 Q = ffi::KEY_Q,
174 R = ffi::KEY_R,
175 S = ffi::KEY_S,
176 T = ffi::KEY_T,
177 U = ffi::KEY_U,
178 V = ffi::KEY_V,
179 W = ffi::KEY_W,
180 X = ffi::KEY_X,
181 Y = ffi::KEY_Y,
182 Z = ffi::KEY_Z,
183 LeftBracket = ffi::KEY_LEFT_BRACKET,
184 Backslash = ffi::KEY_BACKSLASH,
185 RightBracket = ffi::KEY_RIGHT_BRACKET,
186 GraveAccent = ffi::KEY_GRAVE_ACCENT,
187 World1 = ffi::KEY_WORLD_1,
188 World2 = ffi::KEY_WORLD_2,
189
190 Escape = ffi::KEY_ESCAPE,
191 Enter = ffi::KEY_ENTER,
192 Tab = ffi::KEY_TAB,
193 Backspace = ffi::KEY_BACKSPACE,
194 Insert = ffi::KEY_INSERT,
195 Delete = ffi::KEY_DELETE,
196 Right = ffi::KEY_RIGHT,
197 Left = ffi::KEY_LEFT,
198 Down = ffi::KEY_DOWN,
199 Up = ffi::KEY_UP,
200 PageUp = ffi::KEY_PAGE_UP,
201 PageDown = ffi::KEY_PAGE_DOWN,
202 Home = ffi::KEY_HOME,
203 End = ffi::KEY_END,
204 CapsLock = ffi::KEY_CAPS_LOCK,
205 ScrollLock = ffi::KEY_SCROLL_LOCK,
206 NumLock = ffi::KEY_NUM_LOCK,
207 PrintScreen = ffi::KEY_PRINT_SCREEN,
208 Pause = ffi::KEY_PAUSE,
209 F1 = ffi::KEY_F1,
210 F2 = ffi::KEY_F2,
211 F3 = ffi::KEY_F3,
212 F4 = ffi::KEY_F4,
213 F5 = ffi::KEY_F5,
214 F6 = ffi::KEY_F6,
215 F7 = ffi::KEY_F7,
216 F8 = ffi::KEY_F8,
217 F9 = ffi::KEY_F9,
218 F10 = ffi::KEY_F10,
219 F11 = ffi::KEY_F11,
220 F12 = ffi::KEY_F12,
221 F13 = ffi::KEY_F13,
222 F14 = ffi::KEY_F14,
223 F15 = ffi::KEY_F15,
224 F16 = ffi::KEY_F16,
225 F17 = ffi::KEY_F17,
226 F18 = ffi::KEY_F18,
227 F19 = ffi::KEY_F19,
228 F20 = ffi::KEY_F20,
229 F21 = ffi::KEY_F21,
230 F22 = ffi::KEY_F22,
231 F23 = ffi::KEY_F23,
232 F24 = ffi::KEY_F24,
233 F25 = ffi::KEY_F25,
234 Kp0 = ffi::KEY_KP_0,
235 Kp1 = ffi::KEY_KP_1,
236 Kp2 = ffi::KEY_KP_2,
237 Kp3 = ffi::KEY_KP_3,
238 Kp4 = ffi::KEY_KP_4,
239 Kp5 = ffi::KEY_KP_5,
240 Kp6 = ffi::KEY_KP_6,
241 Kp7 = ffi::KEY_KP_7,
242 Kp8 = ffi::KEY_KP_8,
243 Kp9 = ffi::KEY_KP_9,
244 KpDecimal = ffi::KEY_KP_DECIMAL,
245 KpDivide = ffi::KEY_KP_DIVIDE,
246 KpMultiply = ffi::KEY_KP_MULTIPLY,
247 KpSubtract = ffi::KEY_KP_SUBTRACT,
248 KpAdd = ffi::KEY_KP_ADD,
249 KpEnter = ffi::KEY_KP_ENTER,
250 KpEqual = ffi::KEY_KP_EQUAL,
251 LeftShift = ffi::KEY_LEFT_SHIFT,
252 LeftControl = ffi::KEY_LEFT_CONTROL,
253 LeftAlt = ffi::KEY_LEFT_ALT,
254 LeftSuper = ffi::KEY_LEFT_SUPER,
255 RightShift = ffi::KEY_RIGHT_SHIFT,
256 RightControl = ffi::KEY_RIGHT_CONTROL,
257 RightAlt = ffi::KEY_RIGHT_ALT,
258 RightSuper = ffi::KEY_RIGHT_SUPER,
259 Menu = ffi::KEY_MENU,
260 Unknown = ffi::KEY_UNKNOWN
261 }
262
263 /// Wrapper around 'glfwGetKeyName`
get_key_name(key: Option<Key>, scancode: Option<Scancode>) -> Option<String>264 pub fn get_key_name(key: Option<Key>, scancode: Option<Scancode>) -> Option<String> {
265 unsafe {
266 string_from_nullable_c_str(ffi::glfwGetKeyName(match key {
267 Some(k) => k as c_int,
268 None => ffi::KEY_UNKNOWN
269 }, scancode.unwrap_or(ffi::KEY_UNKNOWN)))
270 }
271 }
272
273 /// Wrapper around 'glfwGetKeyName`
274 #[deprecated(since = "0.16.0", note = "'key_name' can cause a segfault, use 'get_key_name' instead")]
key_name(key: Option<Key>, scancode: Option<Scancode>) -> String275 pub fn key_name(key: Option<Key>, scancode: Option<Scancode>) -> String {
276 unsafe {
277 string_from_c_str(ffi::glfwGetKeyName(match key {
278 Some(k) => k as c_int,
279 None => ffi::KEY_UNKNOWN
280 }, scancode.unwrap_or(ffi::KEY_UNKNOWN)))
281 }
282 }
283
284 /// Wrapper around `glfwGetKeyScancode`.
get_key_scancode(key: Option<Key>) -> Option<Scancode>285 pub fn get_key_scancode(key: Option<Key>) -> Option<Scancode> {
286 unsafe {
287 match ffi::glfwGetKeyScancode(match key {
288 Some(key) => key as c_int,
289 None => ffi::KEY_UNKNOWN,
290 }) {
291 ffi::KEY_UNKNOWN => None,
292 scancode => Some(scancode as Scancode),
293 }
294 }
295 }
296
297 impl Key {
298 /// Wrapper around 'glfwGetKeyName` without scancode
299 #[deprecated(since = "0.16.0", note = "Key method 'name' can cause a segfault, use 'get_name' instead")]
name(&self) -> String300 pub fn name(&self) -> String {
301 #[allow(deprecated)]
302 key_name(Some(*self), None)
303 }
304
305 /// Wrapper around 'glfwGetKeyName` without scancode
get_name(&self) -> Option<String>306 pub fn get_name(&self) -> Option<String> {
307 get_key_name(Some(*self), None)
308 }
309
310 /// Wrapper around `glfwGetKeyScancode`.
get_scancode(&self) -> Option<Scancode>311 pub fn get_scancode(&self) -> Option<Scancode> {
312 get_key_scancode(Some(*self))
313 }
314 }
315
316 /// Mouse buttons. The `MouseButtonLeft`, `MouseButtonRight`, and
317 /// `MouseButtonMiddle` aliases are supplied for convenience.
318 #[repr(i32)]
319 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
320 pub enum MouseButton {
321 /// The left mouse button. A `MouseButtonLeft` alias is provided to improve clarity.
322 Button1 = ffi::MOUSE_BUTTON_1,
323 /// The right mouse button. A `MouseButtonRight` alias is provided to improve clarity.
324 Button2 = ffi::MOUSE_BUTTON_2,
325 /// The middle mouse button. A `MouseButtonMiddle` alias is provided to improve clarity.
326 Button3 = ffi::MOUSE_BUTTON_3,
327 Button4 = ffi::MOUSE_BUTTON_4,
328 Button5 = ffi::MOUSE_BUTTON_5,
329 Button6 = ffi::MOUSE_BUTTON_6,
330 Button7 = ffi::MOUSE_BUTTON_7,
331 Button8 = ffi::MOUSE_BUTTON_8,
332 }
333
334 impl MouseButton {
335 /// Converts from `i32`.
from_i32(n: i32) -> Option<MouseButton>336 pub fn from_i32(n: i32) -> Option<MouseButton> {
337 if n >= 0 && n <= ffi::MOUSE_BUTTON_LAST {
338 Some(unsafe { mem::transmute(n) })
339 } else {
340 None
341 }
342 }
343 }
344
345 /// Formats the type using aliases rather than the default variant names.
346 ///
347 /// # Example
348 ///
349 /// ~~~ignore
350 /// assert_eq(format!("{}", glfw::MouseButtonLeft), "MouseButton1");
351 /// assert_eq(format!("{}", glfw::DebugAliases(glfw::MouseButtonLeft)), "MouseButtonLeft");
352 /// ~~~
353 pub struct DebugAliases<T>(pub T);
354
355 impl fmt::Debug for DebugAliases<MouseButton> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result356 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
357 let DebugAliases(button) = *self;
358 match button {
359 MouseButtonLeft => write!(f, "MouseButtonLeft"),
360 MouseButtonRight => write!(f, "MouseButtonRight"),
361 MouseButtonMiddle => write!(f, "MouseButtonMiddle"),
362 button => button.fmt(f),
363 }
364 }
365 }
366
367 #[derive(Copy, Clone)]
368 pub struct Callback<Fn, UserData> {
369 pub f: Fn,
370 pub data: UserData,
371 }
372
373 /// Tokens corresponding to various error types.
374 #[repr(i32)]
375 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
376 pub enum Error {
377 NoError = ffi::NO_ERROR,
378 NotInitialized = ffi::NOT_INITIALIZED,
379 NoCurrentContext = ffi::NO_CURRENT_CONTEXT,
380 InvalidEnum = ffi::INVALID_ENUM,
381 InvalidValue = ffi::INVALID_VALUE,
382 OutOfMemory = ffi::OUT_OF_MEMORY,
383 ApiUnavailable = ffi::API_UNAVAILABLE,
384 VersionUnavailable = ffi::VERSION_UNAVAILABLE,
385 PlatformError = ffi::PLATFORM_ERROR,
386 FormatUnavailable = ffi::FORMAT_UNAVAILABLE,
387 NoWindowContext = ffi::NO_WINDOW_CONTEXT,
388 }
389
390 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result391 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
392 use std::error::Error;
393
394 f.write_str(self.description())
395 }
396 }
397
398 impl error::Error for Error {
description(&self) -> &str399 fn description(&self) -> &str {
400 match *self {
401 Error::NoError => "NoError",
402 Error::NotInitialized => "NotInitialized",
403 Error::NoCurrentContext => "NoCurrentContext",
404 Error::InvalidEnum => "InvalidEnum",
405 Error::InvalidValue => "InvalidValue",
406 Error::OutOfMemory => "OutOfMemory",
407 Error::ApiUnavailable => "ApiUnavailable",
408 Error::VersionUnavailable => "VersionUnavailable",
409 Error::PlatformError => "PlatformError",
410 Error::FormatUnavailable => "FormatUnavailable",
411 Error::NoWindowContext => "NoWindowContext",
412 }
413 }
414 }
415
416 /// An error callback. This can be supplied with some user data to be passed to
417 /// the callback function when it is triggered.
418 pub type ErrorCallback<UserData> = Callback<fn(Error, String, &UserData), UserData>;
419
420 /// The function to be used with the `FAIL_ON_ERRORS` callback.
fail_on_errors(_: Error, description: String, _: &())421 pub fn fail_on_errors(_: Error, description: String, _: &()) {
422 panic!("GLFW Error: {}", description);
423 }
424
425 /// A callback that triggers a task failure when an error is encountered.
426 pub static FAIL_ON_ERRORS: Option<ErrorCallback<()>> =
427 Some(Callback { f: fail_on_errors as fn(Error, String, &()), data: () });
428
429 /// The function to be used with the `LOG_ERRORS` callback.
log_errors(_: Error, description: String, _: &())430 pub fn log_errors(_: Error, description: String, _: &()) {
431 error!("GLFW Error: {}", description);
432 }
433
434 /// A callback that logs each error as it is encountered without triggering a
435 /// task failure.
436 pub static LOG_ERRORS: Option<ErrorCallback<()>> =
437 Some(Callback { f: log_errors as fn(Error, String, &()), data: () });
438
439 /// When not using the `image` library, or if you just want to,
440 /// you can specify an image from its raw pixel data using this structure.
441 pub struct PixelImage {
442 /// Width of the image in pixels
443 pub width: u32,
444 /// Height of the image in pixels
445 pub height: u32,
446 /// Pixels are 4 bytes each, one byte for each RGBA subpixel.
447 pub pixels: Vec<u32>
448 }
449
450 /// Cursor modes.
451 #[repr(i32)]
452 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
453 pub enum CursorMode {
454 Normal = ffi::CURSOR_NORMAL,
455 Hidden = ffi::CURSOR_HIDDEN,
456 Disabled = ffi::CURSOR_DISABLED,
457 }
458
459 /// Standard cursors provided by GLFW
460 #[repr(i32)]
461 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
462 pub enum StandardCursor {
463 /// The regular arrow cursor shape.
464 Arrow = ffi::ARROW_CURSOR,
465 /// The text input I-beam cursor shape.
466 IBeam = ffi::IBEAM_CURSOR,
467 /// The crosshair shape.
468 Crosshair = ffi::CROSSHAIR_CURSOR,
469 /// The hand shape.
470 Hand = ffi::HAND_CURSOR,
471 /// The horizontal resize arrow shape.
472 HResize = ffi::HRESIZE_CURSOR,
473 /// The vertical resize arrow shape.
474 VResize = ffi::VRESIZE_CURSOR
475 }
476
477 /// Represents a window cursor that can be used to display any
478 /// of the standard cursors or load a custom cursor from an image.
479 ///
480 /// Note that the cursor object has a lifetime and will not display
481 /// correctly after it has been dropped.
482 pub struct Cursor {
483 ptr: *mut ffi::GLFWcursor
484 }
485
486 impl Drop for Cursor {
drop(&mut self)487 fn drop(&mut self) {
488 unsafe { ffi::glfwDestroyCursor(self.ptr) }
489 }
490 }
491
492 impl Cursor {
493 /// Create a new cursor using `glfwCreateStandardCursor`
standard(cursor: StandardCursor) -> Cursor494 pub fn standard(cursor: StandardCursor) -> Cursor {
495 Cursor {
496 ptr: unsafe { ffi::glfwCreateStandardCursor(cursor as c_int) }
497 }
498 }
499
500 /// Creates a new cursor from the image provided via `glfwCreateCursor`
501 ///
502 /// Note that the cursor image will be the same size as the image provided,
503 /// so scaling it beforehand may be required.
504 ///
505 /// The cursor hotspot is specified in pixels, relative to the upper-left
506 /// corner of the cursor image. Like all other coordinate systems in GLFW,
507 /// the X-axis points to the right and the Y-axis points down.
508 #[cfg(feature = "image")]
create(image: image::RgbaImage, x_hotspot: u32, y_hotspot: u32) -> Cursor509 pub fn create(image: image::RgbaImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
510 let (width, height) = image.dimensions();
511
512 let image_data = image.into_vec();
513
514 let glfw_image = ffi::GLFWimage {
515 width: width as c_int,
516 height: height as c_int,
517 pixels: image_data.as_ptr() as *const c_uchar
518 };
519
520 Cursor {
521 ptr: unsafe { ffi::glfwCreateCursor(&glfw_image as *const ffi::GLFWimage, x_hotspot as c_int, y_hotspot as c_int) }
522 }
523 }
524
525 /// Creates a new cursor from the `PixelImage` provided via `glfwCreateCursor`
526 ///
527 /// Note that the cursor image will be the same size as the image provided,
528 /// so scaling it beforehand may be required.
529 ///
530 /// The cursor hotspot is specified in pixels, relative to the upper-left
531 /// corner of the cursor image. Like all other coordinate systems in GLFW,
532 /// the X-axis points to the right and the Y-axis points down.
create_from_pixels(image: PixelImage, x_hotspot: u32, y_hotspot: u32) -> Cursor533 pub fn create_from_pixels(image: PixelImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
534 let glfw_image = ffi::GLFWimage {
535 width: image.width as c_int,
536 height: image.height as c_int,
537 pixels: image.pixels.as_ptr() as *const c_uchar
538 };
539
540 Cursor {
541 ptr: unsafe { ffi::glfwCreateCursor(&glfw_image as *const ffi::GLFWimage, x_hotspot as c_int, y_hotspot as c_int) }
542 }
543 }
544 }
545
546 /// Describes a single video mode.
547 #[derive(Copy, Clone)]
548 pub struct VidMode {
549 pub width: u32,
550 pub height: u32,
551 pub red_bits: u32,
552 pub green_bits: u32,
553 pub blue_bits: u32,
554 pub refresh_rate: u32,
555 }
556
557 /// Describes the gamma ramp of a monitor.
558 pub struct GammaRamp {
559 pub red: Vec<c_ushort>,
560 pub green: Vec<c_ushort>,
561 pub blue: Vec<c_ushort>,
562 }
563
564 /// `ContextReleaseBehavior` specifies the release behavior to be used by the context.
565 #[repr(i32)]
566 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
567 pub enum ContextReleaseBehavior {
568 Any = ffi::ANY_RELEASE_BEHAVIOR,
569 /// `Flush` tells the context to flush the pipeline whenever the context is released from being the current one.
570 Flush = ffi::RELEASE_BEHAVIOR_FLUSH,
571 /// `None` tells the context to NOT flush the pipeline on release
572 None = ffi::RELEASE_BEHAVIOR_NONE
573 }
574
575 /// Specifies the API to use to create the context
576 #[repr(i32)]
577 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
578 pub enum ContextCreationApi {
579 Native = ffi::NATIVE_CONTEXT_API,
580 Egl = ffi::EGL_CONTEXT_API,
581 OsMesa = ffi::OSMESA_CONTEXT_API,
582 }
583
584 /// Specifies how the context should handle swapping the buffers.
585 ///
586 /// i.e. the number of screen updates to wait from the time
587 /// `glfwSwapBuffers`/`context.swap_buffers`
588 /// was called before swapping the buffers and returning.
589 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
590 pub enum SwapInterval {
591 /// Specifies no waits
592 None,
593 /// If either of the `WGL_EXT_swap_control_tear` and `GLX_EXT_swap_control_tear` extensions
594 /// are enabled, allows the adaptively swap the frame. Sometimes called Adaptive V-sync
595 Adaptive,
596 /// Synchronizes the buffers every N frames. Set to 1 for V-sync
597 Sync(u32)
598 }
599
600 /// An OpenGL process address.
601 pub type GLProc = ffi::GLFWglproc;
602
603 /// A Vulkan process address
604 #[cfg(feature = "vulkan")]
605 pub type VkProc = ffi::GLFWvkproc;
606
607 /// Counts for (Calling glfwInit) - (Calling glfwTerminate)
608 /// It uses for "global" refference counting for Glfw.
609 static REF_COUNT_FOR_GLFW: AtomicUsize = AtomicUsize::new(0);
610
611 /// A token from which to call various GLFW functions. It can be obtained by
612 /// calling the `init` function. This cannot be sent to other tasks, and should
613 /// only be initialized on the main platform thread. Whilst this might make
614 /// performing some operations harder, this is to ensure thread safety is enforced
615 /// statically.
616 pub struct Glfw;
617
618 /// An error that might be returned when `glfw::init` is called.
619 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
620 pub enum InitError {
621 /// Deprecated. Does not occur.
622 AlreadyInitialized,
623 /// An internal error occurred when trying to initialize the library.
624 Internal,
625 }
626
627 impl fmt::Display for InitError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result628 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
629 use std::error::Error;
630
631 f.write_str(self.description())
632 }
633 }
634
635 impl error::Error for InitError {
description(&self) -> &str636 fn description(&self) -> &str {
637 match *self {
638 InitError::AlreadyInitialized => "Already Initialized",
639 InitError::Internal => "Internal Initialization Error",
640 }
641 }
642 }
643
644 /// Initialization hints that can be set using the `init_hint` function.
645 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
646 pub enum InitHint {
647 /// Specifies whether to also expose joystick hats as buttons, for compatibility with ealier
648 /// versions of GLFW that did not have `glfwGetJoystickHats`.
649 JoystickHatButtons(bool),
650 /// Specifies whether to set the current directory to the application to the `Contents/Resources`
651 /// subdirectory of the application's bundle, if present.
652 ///
653 /// This is ignored on platforms besides macOS.
654 CocoaChdirResources(bool),
655 /// Specifies whether to create a basic menu bar, either from a nib or manually, when the first
656 /// window is created, which is when AppKit is initialized.
657 ///
658 /// This is ignored on platforms besides macOS.
659 CocoaMenubar(bool),
660 }
661
662 /// Sets hints for the next initialization of GLFW.
663 ///
664 /// The values you set hints to are never reset by GLFW, but they only take effect during
665 /// initialization. Once GLFW has been initialized, any values you set will be ignored until the
666 /// library is terminated and initialized again.
667 ///
668 /// Wrapper for `glfwInitHint`.
init_hint(hint: InitHint)669 pub fn init_hint(hint: InitHint) {
670 match hint {
671 InitHint::JoystickHatButtons(joystick_hat_buttons) => unsafe { ffi::glfwInitHint(ffi::JOYSTICK_HAT_BUTTONS, joystick_hat_buttons as c_int) },
672 InitHint::CocoaChdirResources(chdir) => unsafe { ffi::glfwInitHint(ffi::COCOA_CHDIR_RESOURCES, chdir as c_int) },
673 InitHint::CocoaMenubar(menubar) => unsafe { ffi::glfwInitHint(ffi::COCOA_MENUBAR, menubar as c_int) },
674 }
675 }
676
677 /// Initializes the GLFW library. This must be called on the main platform
678 /// thread.
679 ///
680 /// Wrapper for `glfwInit`.
681 ///
682 /// # Error callback
683 ///
684 /// An error callback can be set if desired. This allows for the handling of any
685 /// errors that occur during initialization. This can subsequently be changed
686 /// using the `Glfw::set_error_callback` function.
687 ///
688 /// # Example
689 ///
690 /// ~~~no_run
691 /// extern crate glfw;
692 ///
693 /// fn main() {
694 /// let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
695 /// }
696 /// ~~~
697 ///
698 /// # Returns
699 ///
700 /// - If initialization was successful a `Glfw` token will be returned along
701 /// with a `Receiver` from which errors can be intercepted.
702 /// - Subsequent calls to `init` will return `Glfw` token immediately.
703 /// - If an initialization error occurred within the GLFW library
704 /// `Err(InternalInitError)` will be returned.
init<UserData: 'static>( mut callback: Option<ErrorCallback<UserData>>, ) -> Result<Glfw, InitError>705 pub fn init<UserData: 'static>(
706 mut callback: Option<ErrorCallback<UserData>>,
707 ) -> Result<Glfw, InitError> {
708 // Initialize the error callback if it was supplied. This is done
709 // before `ffi::glfwInit` because errors could occur during
710 // initialization.
711 match callback.take() {
712 Some(f) => callbacks::error::set(f),
713 None => callbacks::error::unset(),
714 }
715 // initialize GLFW.
716 // FYI: multiple not terminated ffi::glfwInit() returns ffi::TRUE immediately.
717 // https://www.glfw.org/docs/latest/group__init.html#ga317aac130a235ab08c6db0834907d85e
718 if unsafe { ffi::glfwInit() } == ffi::TRUE {
719 REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
720 Ok(Glfw)
721 } else {
722 Err(InitError::Internal)
723 }
724 }
725
726 impl Glfw {
727 /// Sets the error callback, overwriting the previous one stored.
728 ///
729 /// # Example
730 ///
731 /// ~~~ignore
732 /// use std::cell::Cell;
733 ///
734 /// fn error_callback(_: glfw::Error, description: String, error_count: &Cell<usize>) {
735 /// println!("GLFW error {}: {}", error_count.get(), description);
736 /// error_count.set(error_count.get() + 1);
737 /// }
738 ///
739 /// // sets a new callback
740 /// glfw.set_error_callback(Some(
741 /// glfw::Callback {
742 /// f: error_callback,
743 /// data: Cell::new(0),
744 /// }
745 /// ));
746 ///
747 /// // removes the previously set callback
748 /// glfw.set_error_callback(None);
749 /// ~~~
750 ///
751 /// The `FAIL_ON_ERRORS` and `LOG_ERRORS` callbacks are provided for
752 /// convenience. For example:
753 ///
754 /// ~~~ignore
755 /// // triggers a task failure when a GLFW error is encountered.
756 /// glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
757 /// ~~~
set_error_callback<UserData: 'static>(&mut self, callback: Option<ErrorCallback<UserData>>)758 pub fn set_error_callback<UserData: 'static>(&mut self, callback: Option<ErrorCallback<UserData>>) {
759 match callback {
760 Some(f) => callbacks::error::set(f),
761 None => callbacks::error::unset(),
762 }
763 }
764
765 /// Sets the monitor callback, overwriting the previous one stored.
set_monitor_callback<UserData: 'static>(&mut self, callback: Option<MonitorCallback<UserData>>)766 pub fn set_monitor_callback<UserData: 'static>(&mut self, callback: Option<MonitorCallback<UserData>>) {
767 match callback {
768 Some(f) => callbacks::monitor::set(f),
769 None => callbacks::monitor::unset(),
770 }
771 }
772
773 /// Sets the joystick callback, overwriting the previous one stored
set_joystick_callback<UserData: 'static>(&mut self, callback: Option<JoystickCallback<UserData>>)774 pub fn set_joystick_callback<UserData: 'static>(&mut self, callback: Option<JoystickCallback<UserData>>) {
775 match callback {
776 Some(f) => callbacks::joystick::set(f),
777 None => callbacks::joystick::unset(),
778 }
779 }
780
781 /// Supplies the primary monitor to the closure provided, if it exists.
782 /// This is usually the monitor where elements like the Windows task bar or
783 /// the OS X menu bar is located.
784 ///
785 /// # Example
786 ///
787 /// ~~~ignore
788 /// let (window, events) = glfw.with_primary_monitor(|_, m| {
789 /// glfw.create_window(300, 300, "Hello this is window",
790 /// m.map_or(glfw::WindowMode::Windowed, |m| glfw::FullScreen(m)))
791 /// }).expect("Failed to create GLFW window.");
792 /// ~~~
with_primary_monitor<T, F>(&mut self, f: F) -> T where F: Fn(&mut Self, Option<&Monitor>) -> T793 pub fn with_primary_monitor<T, F>(&mut self, f: F) -> T where F: Fn(&mut Self, Option<&Monitor>) -> T {
794 match unsafe { ffi::glfwGetPrimaryMonitor() } {
795 ptr if ptr.is_null() => f(self, None),
796 ptr => f(self, Some(&Monitor {
797 ptr: ptr
798 })),
799 }
800 }
801
802 /// Supplies the primary monitor to the closure provided, if it exists.
803 /// This is usually the monitor where elements like the Windows task bar or
804 /// the OS X menu bar is located.
805 ///
806 /// Variant that can accept an `FnMut` closure.
807 ///
808 /// # Example
809 ///
810 /// ~~~ignore
811 /// glfw.with_primary_monitor(|_: &mut _, m: Option<&glfw::Monitor>| {
812 /// let monitor = m.unwrap();
813 ///
814 /// let mode: glfw::VidMode = monitor.get_video_mode().unwrap();
815 ///
816 /// // Modifying `window` requires `FnMut`
817 /// window.set_monitor(glfw::WindowMode::FullScreen(&monitor), 0, 0, mode.width, mode.height, Some(mode.refresh_rate));
818 /// });
819 /// ~~~
with_primary_monitor_mut<T, F>(&mut self, mut f: F) -> T where F: FnMut(&mut Self, Option<&Monitor>) -> T820 pub fn with_primary_monitor_mut<T, F>(&mut self, mut f: F) -> T where F: FnMut(&mut Self, Option<&Monitor>) -> T {
821 match unsafe { ffi::glfwGetPrimaryMonitor() } {
822 ptr if ptr.is_null() => f(self, None),
823 ptr => f(self, Some(&Monitor {
824 ptr: ptr
825 })),
826 }
827 }
828
829 /// Supplies a vector of the currently connected monitors to the closure
830 /// provided.
831 ///
832 /// # Example
833 ///
834 /// ~~~ignore
835 /// glfw.with_connected_monitors(|_, monitors| {
836 /// for monitor in monitors.iter() {
837 /// println!("{}: {}", monitor.get_name(), monitor.get_video_mode());
838 /// }
839 /// });
840 /// ~~~
with_connected_monitors<T, F>(&mut self, f: F) -> T where F: Fn(&mut Self, &[Monitor]) -> T841 pub fn with_connected_monitors<T, F>(&mut self, f: F) -> T where F: Fn(&mut Self, &[Monitor]) -> T {
842 unsafe {
843 let mut count = 0;
844 let ptr = ffi::glfwGetMonitors(&mut count);
845 f(self,
846 &slice::from_raw_parts(ptr as *const _, count as usize).iter().map(|&ptr| {
847 Monitor {
848 ptr: ptr
849 }
850 }).collect::<Vec<Monitor>>())
851 }
852 }
853
854 /// Supplies a vector of the currently connected monitors to the closure
855 /// provided.
856 ///
857 /// Variant that can accept an `FnMut` closure.
858 ///
859 /// # Example
860 ///
861 /// ~~~ignore
862 /// glfw.with_connected_monitors(|_, monitors| {
863 /// for monitor in monitors.iter() {
864 /// println!("{}: {}", monitor.get_name(), monitor.get_video_mode());
865 /// }
866 /// });
867 /// ~~~
with_connected_monitors_mut<T, F>(&mut self, mut f: F) -> T where F: FnMut(&mut Self, &[Monitor]) -> T868 pub fn with_connected_monitors_mut<T, F>(&mut self, mut f: F) -> T where F: FnMut(&mut Self, &[Monitor]) -> T {
869 unsafe {
870 let mut count = 0;
871 let ptr = ffi::glfwGetMonitors(&mut count);
872 f(self,
873 &slice::from_raw_parts(ptr as *const _, count as usize).iter().map(|&ptr| {
874 Monitor {
875 ptr: ptr
876 }
877 }).collect::<Vec<Monitor>>())
878 }
879 }
880
881 /// Queries Vulkan support via `glfwVulkanSupported`
882 #[cfg(feature = "vulkan")]
vulkan_supported(&self) -> bool883 pub fn vulkan_supported(&self) -> bool {
884 unsafe { ffi::glfwVulkanSupported() == ffi::TRUE }
885 }
886
887 /// This is used to set the window hints for the next call to
888 /// `Glfw::create_window`. The hints can be reset to their default values
889 /// using calling the `Glfw::default_window_hints` function.
890 ///
891 /// Wrapper for `glfwWindowHint`
892 ///
893 /// # OpenGL 3.x and 4.x on Mac OS X
894 ///
895 /// The only OpenGL 3.x and 4.x contexts supported by OS X are
896 /// forward-compatible, core profile contexts.
897 ///
898 /// 10.7 and 10.8 support the following OpenGL versions:
899 ///
900 /// - `glfw::WindowHint::ContextVersion(3, 2)`
901 ///
902 /// 10.9 supports the following OpenGL versions
903 ///
904 /// - `glfw::WindowHint::ContextVersion(3, 2)`
905 /// - `glfw::WindowHint::ContextVersion(3, 3)`
906 /// - `glfw::WindowHint::ContextVersion(4, 1)`
907 ///
908 /// To create an OS X compatible context, the hints should be specified as
909 /// follows:
910 ///
911 /// ~~~ignore
912 /// glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
913 /// glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
914 /// glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
915 /// ~~~
window_hint(&mut self, hint: WindowHint)916 pub fn window_hint(&mut self, hint: WindowHint) {
917 //This is just a simple function to unwrap the option and convert it to `c_int` or use `GLFW_DONT_CARE`,
918 //then call `glfwWindowHint` with the result. It was required because `GLFW_DONT_CARE` is signed,
919 //so `value.unwrap_or(ffi::DONT_CARE)` wouldn't work because of the type difference.
920 #[inline(always)]
921 unsafe fn dont_care_hint(hint: c_int, value: Option<u32>) {
922 ffi::glfwWindowHint(hint, match value {
923 Some(v) => v as c_int,
924 None => ffi::DONT_CARE
925 })
926 }
927
928 #[inline(always)]
929 unsafe fn string_hint(hint: c_int, value: Option<String>) {
930 let value = if let Some(value) = &value {
931 value.as_str()
932 } else {
933 ""
934 };
935 with_c_str(value, |value| {
936 ffi::glfwWindowHintString(hint, value)
937 })
938 }
939
940 match hint {
941 WindowHint::RedBits(bits) => unsafe { dont_care_hint(ffi::RED_BITS, bits) },
942 WindowHint::GreenBits(bits) => unsafe { dont_care_hint(ffi::GREEN_BITS, bits) },
943 WindowHint::BlueBits(bits) => unsafe { dont_care_hint(ffi::BLUE_BITS, bits) },
944 WindowHint::AlphaBits(bits) => unsafe { dont_care_hint(ffi::ALPHA_BITS, bits) },
945 WindowHint::DepthBits(bits) => unsafe { dont_care_hint(ffi::DEPTH_BITS, bits) },
946 WindowHint::StencilBits(bits) => unsafe { dont_care_hint(ffi::STENCIL_BITS, bits) },
947 WindowHint::AccumRedBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_RED_BITS, bits) },
948 WindowHint::AccumGreenBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_GREEN_BITS, bits) },
949 WindowHint::AccumBlueBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_BLUE_BITS, bits) },
950 WindowHint::AccumAlphaBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_ALPHA_BITS, bits) },
951 WindowHint::AuxBuffers(num_buffers) => unsafe { dont_care_hint(ffi::AUX_BUFFERS, num_buffers) },
952 WindowHint::Samples(num_samples) => unsafe { dont_care_hint(ffi::SAMPLES, num_samples) },
953 WindowHint::RefreshRate(rate) => unsafe { dont_care_hint(ffi::REFRESH_RATE, rate) },
954 WindowHint::Stereo(is_stereo) => unsafe { ffi::glfwWindowHint(ffi::STEREO, is_stereo as c_int) },
955 WindowHint::SRgbCapable(is_capable) => unsafe { ffi::glfwWindowHint(ffi::SRGB_CAPABLE, is_capable as c_int) },
956 WindowHint::ClientApi(api) => unsafe { ffi::glfwWindowHint(ffi::CLIENT_API, api as c_int) },
957 WindowHint::ContextVersionMajor(major) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MAJOR, major as c_int) },
958 WindowHint::ContextVersionMinor(minor) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MINOR, minor as c_int) },
959 WindowHint::ContextVersion(major, minor) => unsafe {
960 ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MAJOR, major as c_int);
961 ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MINOR, minor as c_int)
962 },
963 WindowHint::ContextRobustness(robustness) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_ROBUSTNESS, robustness as c_int) },
964 WindowHint::OpenGlForwardCompat(is_compat) => unsafe { ffi::glfwWindowHint(ffi::OPENGL_FORWARD_COMPAT, is_compat as c_int) },
965 WindowHint::OpenGlDebugContext(is_debug) => unsafe { ffi::glfwWindowHint(ffi::OPENGL_DEBUG_CONTEXT, is_debug as c_int) },
966 WindowHint::OpenGlProfile(profile) => unsafe { ffi::glfwWindowHint(ffi::OPENGL_PROFILE, profile as c_int) },
967 WindowHint::Resizable(is_resizable) => unsafe { ffi::glfwWindowHint(ffi::RESIZABLE, is_resizable as c_int) },
968 WindowHint::Visible(is_visible) => unsafe { ffi::glfwWindowHint(ffi::VISIBLE, is_visible as c_int) },
969 WindowHint::Decorated(is_decorated) => unsafe { ffi::glfwWindowHint(ffi::DECORATED, is_decorated as c_int) },
970 WindowHint::AutoIconify(auto_iconify) => unsafe { ffi::glfwWindowHint(ffi::AUTO_ICONIFY, auto_iconify as c_int) },
971 WindowHint::Floating(is_floating) => unsafe { ffi::glfwWindowHint(ffi::FLOATING, is_floating as c_int) },
972 WindowHint::Focused(is_focused) => unsafe { ffi::glfwWindowHint(ffi::FOCUSED, is_focused as c_int) },
973 WindowHint::ContextNoError(is_no_error) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_NO_ERROR, is_no_error as c_int) },
974 WindowHint::ContextCreationApi(api) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_CREATION_API, api as c_int) },
975 WindowHint::ContextReleaseBehavior(behavior) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_RELEASE_BEHAVIOR, behavior as c_int) },
976 WindowHint::DoubleBuffer(is_dbuffered) => unsafe { ffi::glfwWindowHint(ffi::DOUBLEBUFFER, is_dbuffered as c_int) },
977 WindowHint::CenterCursor(center_cursor) => unsafe { ffi::glfwWindowHint(ffi::CENTER_CURSOR, center_cursor as c_int) },
978 WindowHint::TransparentFramebuffer(is_transparent) => unsafe { ffi::glfwWindowHint(ffi::TRANSPARENT_FRAMEBUFFER, is_transparent as c_int) },
979 WindowHint::FocusOnShow(focus) => unsafe { ffi::glfwWindowHint(ffi::FOCUS_ON_SHOW, focus as c_int) },
980 WindowHint::ScaleToMonitor(scale) => unsafe { ffi::glfwWindowHint(ffi::SCALE_TO_MONITOR, scale as c_int) },
981 WindowHint::CocoaRetinaFramebuffer(retina_fb) => unsafe { ffi::glfwWindowHint(ffi::COCOA_RETINA_FRAMEBUFFER, retina_fb as c_int) },
982 WindowHint::CocoaFrameName(name) => unsafe { string_hint(ffi::COCOA_FRAME_NAME, name) }
983 WindowHint::CocoaGraphicsSwitching(graphics_switching) => unsafe { ffi::glfwWindowHint(ffi::COCOA_GRAPHICS_SWITCHING, graphics_switching as c_int) },
984 WindowHint::X11ClassName(class_name) => unsafe { string_hint(ffi::X11_CLASS_NAME, class_name) },
985 WindowHint::X11InstanceName(instance_name) => unsafe { string_hint(ffi::X11_INSTANCE_NAME, instance_name) },
986 }
987 }
988
989 /// Resets the window hints previously set by the `window_hint` function to
990 /// their default values.
991 ///
992 /// Wrapper for `glfwDefaultWindowHints`.
default_window_hints(&mut self)993 pub fn default_window_hints(&mut self) {
994 unsafe { ffi::glfwDefaultWindowHints(); }
995 }
996
997 /// Creates a new window.
998 ///
999 /// Wrapper for `glfwCreateWindow`.
create_window(&self, width: u32, height: u32, title: &str, mode: WindowMode) -> Option<(Window, Receiver<(f64, WindowEvent)>)>1000 pub fn create_window(&self, width: u32, height: u32, title: &str, mode: WindowMode) -> Option<(Window, Receiver<(f64, WindowEvent)>)> {
1001 self.create_window_intern(width, height, title, mode, None)
1002 }
1003
1004 /// Internal wrapper for `glfwCreateWindow`.
create_window_intern(&self, width: u32, height: u32, title: &str, mode: WindowMode, share: Option<&Window>) -> Option<(Window, Receiver<(f64, WindowEvent)>)>1005 fn create_window_intern(&self, width: u32, height: u32, title: &str, mode: WindowMode, share: Option<&Window>) -> Option<(Window, Receiver<(f64, WindowEvent)>)> {
1006 let ptr = unsafe {
1007 with_c_str(title, |title| {
1008 ffi::glfwCreateWindow(
1009 width as c_int,
1010 height as c_int,
1011 title,
1012 mode.to_ptr(),
1013 match share { Some(w) => w.ptr, None => ptr::null_mut() }
1014 )
1015 })
1016 };
1017 if ptr.is_null() {
1018 None
1019 } else {
1020 let (drop_sender, drop_receiver) = channel();
1021 let (sender, receiver) = channel();
1022 unsafe { ffi::glfwSetWindowUserPointer(ptr, mem::transmute(Box::new(sender))); }
1023 Some((
1024 Window {
1025 ptr: ptr,
1026 glfw: self.clone(),
1027 is_shared: share.is_some(),
1028 drop_sender: Some(drop_sender),
1029 drop_receiver: drop_receiver,
1030 current_cursor: None
1031 },
1032 receiver,
1033 ))
1034 }
1035 }
1036
1037 /// Makes the context of the specified window current. If no window is given
1038 /// then the current context is detached.
1039 ///
1040 /// Wrapper for `glfwMakeContextCurrent`.
make_context_current(&mut self, context: Option<&Window>)1041 pub fn make_context_current(&mut self, context: Option<&Window>) {
1042 match context {
1043 Some(window) => unsafe { ffi::glfwMakeContextCurrent(window.ptr) },
1044 None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
1045 }
1046 }
1047
1048 /// Wrapper for `glfwGetX11Display`
1049 #[cfg(target_os="linux")]
get_x11_display(&self) -> *mut c_void1050 pub fn get_x11_display(&self) -> *mut c_void {
1051 unsafe { ffi::glfwGetX11Display() }
1052 }
1053
1054 /// Immediately process the received events.
1055 ///
1056 /// Wrapper for `glfwPollEvents`.
poll_events(&mut self)1057 pub fn poll_events(&mut self) {
1058 unsafe { ffi::glfwPollEvents(); }
1059 }
1060
1061 /// Immediately process the received events. The *unbuffered* variant differs by allowing
1062 /// inspection of events *prior* to their associated native callback returning. This also
1063 /// provides a way to synchronously respond to the event. Events returned by the closure
1064 /// are delivered to the channel receiver just as if `poll_events` was called. Returning
1065 /// `None` from the closure will drop the event.
1066 ///
1067 /// Wrapper for `glfwPollEvents`.
poll_events_unbuffered<F>(&mut self, mut f: F) where F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>1068 pub fn poll_events_unbuffered<F>(&mut self, mut f: F)
1069 where
1070 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>
1071 {
1072 let _unset_handler_guard = unsafe {
1073 crate::callbacks::unbuffered::set_handler(&mut f)
1074 };
1075 self.poll_events();
1076 }
1077
1078 /// Sleep until at least one event has been received, and then perform the
1079 /// equivalent of `Glfw::poll_events`.
1080 ///
1081 /// Wrapper for `glfwWaitEvents`.
wait_events(&mut self)1082 pub fn wait_events(&mut self) {
1083 unsafe { ffi::glfwWaitEvents(); }
1084 }
1085
1086 /// Sleep until at least one event has been received, and then perform the
1087 /// equivalent of `Glfw::poll_events_unbuffered`.
1088 ///
1089 /// Wrapper for `glfwWaitEvents`.
wait_events_unbuffered<F>(&mut self, mut f: F) where F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>1090 pub fn wait_events_unbuffered<F>(&mut self, mut f: F)
1091 where
1092 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>
1093 {
1094 let _unset_handler_guard = unsafe {
1095 crate::callbacks::unbuffered::set_handler(&mut f)
1096 };
1097 self.wait_events();
1098 }
1099
1100 /// Sleep until at least one event has been received, or until the specified
1101 /// timeout is reached, and then perform the equivalent of `Glfw::poll_events`.
1102 /// Timeout is specified in seconds.
1103 ///
1104 /// Wrapper for `glfwWaitEventsTimeout`.
wait_events_timeout(&mut self, timeout: f64)1105 pub fn wait_events_timeout(&mut self, timeout: f64) {
1106 unsafe { ffi::glfwWaitEventsTimeout(timeout); }
1107 }
1108
1109 /// Sleep until at least one event has been received, or until the specified
1110 /// timeout is reached, and then perform the equivalent of `Glfw::poll_events_unbuffered`.
1111 /// Timeout is specified in seconds.
1112 ///
1113 /// Wrapper for `glfwWaitEventsTimeout`.
wait_events_timeout_unbuffered<F>(&mut self, timeout: f64, mut f: F) where F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>1114 pub fn wait_events_timeout_unbuffered<F>(&mut self, timeout: f64, mut f: F)
1115 where
1116 F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>
1117 {
1118 let _unset_handler_guard = unsafe {
1119 crate::callbacks::unbuffered::set_handler(&mut f)
1120 };
1121 self.wait_events_timeout(timeout);
1122 }
1123
1124 /// Posts an empty event from the current thread to the event queue, causing
1125 /// `wait_events` or `wait_events_timeout` to return.
1126 /// If no windows exist, this function returns immediately.
1127 ///
1128 /// Wrapper for `glfwPostEmptyEvent`.
post_empty_event(&mut self)1129 pub fn post_empty_event(&mut self) {
1130 unsafe { ffi::glfwPostEmptyEvent(); }
1131 }
1132
1133 /// Returns the current value of the GLFW timer. Unless the timer has been
1134 /// set using `glfw::set_time`, the timer measures time elapsed since GLFW
1135 /// was initialized.
1136 ///
1137 /// Wrapper for `glfwGetTime`.
get_time(&self) -> f641138 pub fn get_time(&self) -> f64 {
1139 unsafe { ffi::glfwGetTime() as f64 }
1140 }
1141
1142 /// Sets the value of the GLFW timer.
1143 ///
1144 /// Wrapper for `glfwSetTime`.
set_time(&mut self, time: f64)1145 pub fn set_time(&mut self, time: f64) {
1146 unsafe { ffi::glfwSetTime(time as c_double); }
1147 }
1148
1149 /// Wrapper for `glfwGetTimerValue`.
get_timer_value() -> u641150 pub fn get_timer_value() -> u64 {
1151 unsafe { ffi::glfwGetTimerValue() as u64 }
1152 }
1153
1154 /// Wrapper for `glfwGetTimerFrequency`
get_timer_frequency() -> u641155 pub fn get_timer_frequency() -> u64 {
1156 unsafe { ffi::glfwGetTimerFrequency() as u64 }
1157 }
1158
1159 /// Sets the number of screen updates to wait before swapping the buffers of
1160 /// the current context and returning from `Window::swap_buffers`.
1161 ///
1162 /// Wrapper for `glfwSwapInterval`.
set_swap_interval(&mut self, interval: SwapInterval)1163 pub fn set_swap_interval(&mut self, interval: SwapInterval) {
1164 unsafe {
1165 ffi::glfwSwapInterval(match interval {
1166 SwapInterval::None => 0 as c_int,
1167 SwapInterval::Adaptive => -1 as c_int,
1168 SwapInterval::Sync(interval) => interval as c_int
1169 })
1170 }
1171 }
1172
1173 /// Returns `true` if the specified OpenGL or context creation API extension
1174 /// is supported by the current context.
1175 ///
1176 /// Wrapper for `glfwExtensionSupported`.
extension_supported(&self, extension: &str) -> bool1177 pub fn extension_supported(&self, extension: &str) -> bool {
1178 unsafe {
1179 with_c_str(extension, |extension| {
1180 ffi::glfwExtensionSupported(extension) == ffi::TRUE
1181 })
1182 }
1183 }
1184
1185 /// Wrapper for `glfwGetRequiredInstanceExtensions`
1186 ///
1187 /// This function returns a Vector of names of Vulkan instance extensions
1188 /// required by GLFW for creating Vulkan surfaces for GLFW windows. If successful,
1189 /// the list will always contains `VK_KHR_surface`, so if you don't require any
1190 /// additional extensions you can pass this list directly to the `VkInstanceCreateInfo` struct.
1191 ///
1192 /// Will return `None` if the API is unavailable.
1193 #[cfg(feature = "vulkan")]
get_required_instance_extensions(&self) -> Option<Vec<String>>1194 pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
1195 let mut len: c_uint = 0;
1196
1197 unsafe {
1198 let raw_extensions: *const *const c_char = ffi::glfwGetRequiredInstanceExtensions(&mut len as *mut c_uint);
1199
1200 if !raw_extensions.is_null() {
1201 return Some(slice::from_raw_parts(raw_extensions, len as usize)
1202 .iter()
1203 .map(|extensions| string_from_c_str(*extensions))
1204 .collect());
1205 }
1206 }
1207
1208 None
1209 }
1210
1211 /// Returns the address of the specified client API or extension function if
1212 /// it is supported by the current context, NULL otherwise.
1213 ///
1214 /// Wrapper for `glfwGetProcAddress`.
get_proc_address_raw(&self, procname: &str) -> GLProc1215 pub fn get_proc_address_raw(&self, procname: &str) -> GLProc {
1216 debug_assert!(unsafe { ffi::glfwGetCurrentContext() } != std::ptr::null_mut());
1217 with_c_str(procname, |procname| {
1218 unsafe { ffi::glfwGetProcAddress(procname) }
1219 })
1220 }
1221
1222 /// This function returns the address of the specified Vulkan core or extension function
1223 /// for the specified instance. If instance is set to NULL it can return any function
1224 /// exported from the Vulkan loader, including at least the following functions:
1225 ///
1226 /// * `vkEnumerateInstanceExtensionProperties`
1227 /// * `vkEnumerateInstanceLayerProperties`
1228 /// * `vkCreateInstance`
1229 /// * `vkGetInstanceProcAddr`
1230 ///
1231 /// If Vulkan is not available on the machine, this function returns `NULL`
1232 ///
1233 /// Wrapper for `glfwGetInstanceProcAddress`
1234 #[cfg(feature = "vulkan")]
get_instance_proc_address_raw(&self, instance: VkInstance, procname: &str) -> VkProc1235 pub fn get_instance_proc_address_raw(&self, instance: VkInstance, procname: &str) -> VkProc {
1236 with_c_str(procname, |procname| {
1237 unsafe { ffi::glfwGetInstanceProcAddress(instance, procname) }
1238 })
1239 }
1240
1241 /// This function returns whether the specified queue family of the specified
1242 /// physical device supports presentation to the platform GLFW was built for.
1243 ///
1244 /// Wrapper for `glfwGetPhysicalDevicePresentationSupport`
1245 #[cfg(feature = "vulkan")]
get_physical_device_presentation_support_raw(&self, instance: VkInstance, device: VkPhysicalDevice, queue_family: u32) -> bool1246 pub fn get_physical_device_presentation_support_raw(&self, instance: VkInstance, device: VkPhysicalDevice, queue_family: u32) -> bool {
1247 vk::TRUE == unsafe { ffi::glfwGetPhysicalDevicePresentationSupport(instance, device, queue_family as c_uint) as u32 }
1248 }
1249
1250 /// Constructs a `Joystick` handle corresponding to the supplied `JoystickId`.
get_joystick(&self, id: JoystickId) -> Joystick1251 pub fn get_joystick(&self, id: JoystickId) -> Joystick {
1252 Joystick { id: id, glfw: self.clone() }
1253 }
1254
1255 /// Wrapper for `glfwRawMouseMotionSupported`.
supports_raw_motion(&self) -> bool1256 pub fn supports_raw_motion(&self) -> bool {
1257 unsafe { ffi::glfwRawMouseMotionSupported() == ffi::TRUE }
1258 }
1259
1260 /// Parses the specified ASCII encoded string and updates the internal list with any gamepad
1261 /// mappings it finds. This string may contain either a single gamepad mapping or many mappings
1262 /// separated by newlines. The parser supports the full format of the `gamecontrollerdb.txt`
1263 /// source file including empty lines and comments.
1264 ///
1265 /// Wrapper for `glfwUpdateGamepadMappings`.
1266 ///
1267 /// # Returns
1268 ///
1269 /// `true` if successful, or `false` if an error occured.
update_gamepad_mappings(&self, mappings: &str) -> bool1270 pub fn update_gamepad_mappings(&self, mappings: &str) -> bool {
1271 unsafe {
1272 let c_str = CString::new(mappings.as_bytes());
1273 let ptr = c_str.unwrap().as_bytes_with_nul().as_ptr() as *const c_char;
1274 ffi::glfwUpdateGamepadMappings(ptr) == ffi::TRUE
1275 }
1276 }
1277 }
1278
1279 impl Clone for Glfw {
clone(&self) -> Self1280 fn clone(&self) -> Self {
1281 REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
1282 Glfw
1283 }
1284 }
1285
1286 impl Drop for Glfw {
drop(&mut self)1287 fn drop(&mut self) {
1288 let old_diff = REF_COUNT_FOR_GLFW.fetch_sub(1, Ordering::SeqCst);
1289 if old_diff == 1 {
1290 unsafe { ffi::glfwTerminate(); }
1291 }
1292 }
1293 }
1294
1295 /// Wrapper for `glfwGetVersion`.
get_version() -> Version1296 pub fn get_version() -> Version {
1297 unsafe {
1298 let mut major = 0;
1299 let mut minor = 0;
1300 let mut patch = 0;
1301 ffi::glfwGetVersion(&mut major, &mut minor, &mut patch);
1302 Version {
1303 major: major as u64,
1304 minor: minor as u64,
1305 patch: patch as u64,
1306 pre: Vec::new(),
1307 build: Vec::new(),
1308 }
1309 }
1310 }
1311
1312 /// Replacement for `String::from_raw_buf`
string_from_c_str(c_str: *const c_char) -> String1313 pub unsafe fn string_from_c_str(c_str: *const c_char) -> String {
1314 String::from_utf8_lossy(CStr::from_ptr(c_str).to_bytes()).into_owned()
1315 }
1316
1317 /// Like `string_from_c_str`, but handles null pointers correctly
string_from_nullable_c_str(c_str: *const c_char) -> Option<String>1318 pub unsafe fn string_from_nullable_c_str(c_str: *const c_char) -> Option<String> {
1319 if c_str.is_null() {
1320 None
1321 } else {
1322 Some(string_from_c_str(c_str))
1323 }
1324 }
1325
1326 /// Replacement for `ToCStr::with_c_str`
with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const c_char) -> T1327 pub fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const c_char) -> T {
1328 let c_str = CString::new(s.as_bytes());
1329 f(c_str.unwrap().as_bytes_with_nul().as_ptr() as *const _)
1330 }
1331
1332 /// Wrapper for `glfwGetVersionString`.
get_version_string() -> String1333 pub fn get_version_string() -> String {
1334 unsafe { string_from_c_str(ffi::glfwGetVersionString()) }
1335 }
1336
1337 /// An monitor callback. This can be supplied with some user data to be passed
1338 /// to the callback function when it is triggered.
1339 pub type MonitorCallback<UserData> = Callback<fn(Monitor, MonitorEvent, &UserData), UserData>;
1340
1341 /// A struct that wraps a `*GLFWmonitor` handle.
1342 #[allow(missing_copy_implementations)]
1343 pub struct Monitor {
1344 ptr: *mut ffi::GLFWmonitor
1345 }
1346
1347 impl std::fmt::Debug for Monitor {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result1348 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1349 write!(f, "Monitor({:p})", self.ptr)
1350 }
1351 }
1352
1353 impl Monitor {
1354 /// Wrapper for `glfwGetMonitorPos`.
get_pos(&self) -> (i32, i32)1355 pub fn get_pos(&self) -> (i32, i32) {
1356 unsafe {
1357 let mut xpos = 0;
1358 let mut ypos = 0;
1359 ffi::glfwGetMonitorPos(self.ptr, &mut xpos, &mut ypos);
1360 (xpos as i32, ypos as i32)
1361 }
1362 }
1363
1364 /// Wrapper for `glfwGetMonitorPhysicalSize`.
get_physical_size(&self) -> (i32, i32)1365 pub fn get_physical_size(&self) -> (i32, i32) {
1366 unsafe {
1367 let mut width = 0;
1368 let mut height = 0;
1369 ffi::glfwGetMonitorPhysicalSize(self.ptr, &mut width, &mut height);
1370 (width as i32, height as i32)
1371 }
1372 }
1373
1374 /// Wrapper for `glfwGetMonitorName`.
get_name(&self) -> Option<String>1375 pub fn get_name(&self) -> Option<String> {
1376 unsafe { string_from_nullable_c_str(ffi::glfwGetMonitorName(self.ptr)) }
1377 }
1378
1379 /// Wrapper for `glfwGetVideoModes`.
get_video_modes(&self) -> Vec<VidMode>1380 pub fn get_video_modes(&self) -> Vec<VidMode> {
1381 unsafe {
1382 let mut count = 0;
1383 let ptr = ffi::glfwGetVideoModes(self.ptr, &mut count);
1384 slice::from_raw_parts(ptr, count as usize).iter().map(VidMode::from_glfw_vid_mode).collect()
1385 }
1386 }
1387
1388 /// Wrapper for `glfwGetVideoMode`.
get_video_mode(&self) -> Option<VidMode>1389 pub fn get_video_mode(&self) -> Option<VidMode> {
1390 unsafe {
1391 // TODO: Can be returned to as_ref + map as in previous commit when (if?) as_ref stabilizes.
1392 let ptr = ffi::glfwGetVideoMode(self.ptr);
1393 if ptr.is_null() {
1394 None
1395 } else {
1396 Some(VidMode::from_glfw_vid_mode(&*ptr))
1397 }
1398 }
1399 }
1400
1401 /// Wrapper for `glfwSetGamma`.
set_gamma(&mut self, gamma: f32)1402 pub fn set_gamma(&mut self, gamma: f32) {
1403 unsafe { ffi::glfwSetGamma(self.ptr, gamma as c_float); }
1404 }
1405
1406 /// Wrapper for `glfwGetGammaRamp`.
get_gamma_ramp(&self) -> GammaRamp1407 pub fn get_gamma_ramp(&self) -> GammaRamp {
1408 unsafe {
1409 let llramp = *ffi::glfwGetGammaRamp(self.ptr);
1410 GammaRamp {
1411 red: slice::from_raw_parts(llramp.red as *const c_ushort, llramp.size as usize)
1412 .iter().map(|&x| x).collect(),
1413 green: slice::from_raw_parts(llramp.green as *const c_ushort, llramp.size as usize)
1414 .iter().map(|&x| x).collect(),
1415 blue: slice::from_raw_parts(llramp.blue as *const c_ushort, llramp.size as usize)
1416 .iter().map(|&x| x).collect(),
1417 }
1418 }
1419 }
1420
1421 /// Wrapper for `glfwSetGammaRamp`.
set_gamma_ramp(&mut self, ramp: &mut GammaRamp)1422 pub fn set_gamma_ramp(&mut self, ramp: &mut GammaRamp) {
1423 unsafe {
1424 ffi::glfwSetGammaRamp(
1425 self.ptr,
1426 &ffi::GLFWgammaramp {
1427 red: ramp.red.as_mut_ptr(),
1428 green: ramp.green.as_mut_ptr(),
1429 blue: ramp.blue.as_mut_ptr(),
1430 size: ramp.red.len() as u32,
1431 }
1432 );
1433 }
1434 }
1435
1436 /// Wrapper for `glfwGetMonitorContentScale`.
get_content_scale(&self) -> (f32, f32)1437 pub fn get_content_scale(&self) -> (f32, f32) {
1438 unsafe {
1439 let mut xscale = 0.0_f32;
1440 let mut yscale = 0.0_f32;
1441 ffi::glfwGetMonitorContentScale(self.ptr, &mut xscale, &mut yscale);
1442 (xscale, yscale)
1443 }
1444 }
1445
1446 /// Wrapper for `glfwGetMonitorWorkarea`.
get_workarea(&self) -> (i32, i32, i32, i32)1447 pub fn get_workarea(&self) -> (i32, i32, i32, i32) {
1448 unsafe {
1449 let mut xpos = 0;
1450 let mut ypos = 0;
1451 let mut width = 0;
1452 let mut height = 0;
1453 ffi::glfwGetMonitorWorkarea(self.ptr, &mut xpos, &mut ypos, &mut width, &mut height);
1454 (xpos, ypos, width, height)
1455 }
1456 }
1457 }
1458
1459 /// Monitor events.
1460 #[repr(i32)]
1461 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
1462 pub enum MonitorEvent {
1463 Connected = ffi::CONNECTED,
1464 Disconnected = ffi::DISCONNECTED,
1465 }
1466
1467 impl VidMode {
from_glfw_vid_mode(mode: &ffi::GLFWvidmode) -> VidMode1468 fn from_glfw_vid_mode(mode: &ffi::GLFWvidmode) -> VidMode {
1469 VidMode {
1470 width: mode.width as u32,
1471 height: mode.height as u32,
1472 red_bits: mode.redBits as u32,
1473 green_bits: mode.greenBits as u32,
1474 blue_bits: mode.blueBits as u32,
1475 refresh_rate: mode.refreshRate as u32,
1476 }
1477 }
1478 }
1479
1480 impl fmt::Debug for VidMode {
1481 /// Returns a string representation of the video mode.
1482 ///
1483 /// # Returns
1484 ///
1485 /// A string in the form:
1486 ///
1487 /// ~~~ignore
1488 /// ~"[width] x [height], [total_bits] ([red_bits] [green_bits] [blue_bits]) [refresh_rate] Hz"
1489 /// ~~~
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1490 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1491 write!(f, "{} x {}, {} = {} + {} + {}, {} Hz",
1492 self.width, self.height,
1493 self.red_bits + self.green_bits + self.blue_bits,
1494 self.red_bits, self.green_bits, self.blue_bits,
1495 self.refresh_rate)
1496 }
1497 }
1498
1499 /// Window hints that can be set using the `window_hint` function.
1500 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
1501 pub enum WindowHint {
1502 /// Specifies the desired bit depth of the red component of the default framebuffer.
1503 RedBits(Option<u32>),
1504 /// Specifies the desired bit depth of the green component of the default framebuffer.
1505 GreenBits(Option<u32>),
1506 /// Specifies the desired bit depth of the blue component of the default framebuffer.
1507 BlueBits(Option<u32>),
1508 /// Specifies the desired bit depth of the alpha component of the default framebuffer.
1509 AlphaBits(Option<u32>),
1510 /// Specifies the desired bit depth of the depth component of the default framebuffer.
1511 DepthBits(Option<u32>),
1512 /// Specifies the desired bit depth of the stencil component of the default framebuffer.
1513 StencilBits(Option<u32>),
1514 /// Specifies the desired bit depth of the red component of the accumulation framebuffer.
1515 AccumRedBits(Option<u32>),
1516 /// Specifies the desired bit depth of the green component of the accumulation framebuffer.
1517 AccumGreenBits(Option<u32>),
1518 /// Specifies the desired bit depth of the blue component of the accumulation framebuffer.
1519 AccumBlueBits(Option<u32>),
1520 /// Specifies the desired bit depth of the alpha component of the accumulation framebuffer.
1521 AccumAlphaBits(Option<u32>),
1522 /// Specifies the desired number of auxiliary buffers.
1523 AuxBuffers(Option<u32>),
1524 /// Specifies whether to use stereoscopic rendering.
1525 Stereo(bool),
1526 /// Specifies the desired number of samples to use for multisampling. Zero
1527 /// disables multisampling.
1528 Samples(Option<u32>),
1529 /// Specifies whether the framebuffer should be sRGB capable.
1530 SRgbCapable(bool),
1531 /// Specifies the desired refresh rate for full screen windows. If set to `None`,
1532 /// the highest available refresh rate will be used.
1533 ///
1534 /// This hint is ignored for windowed mode windows.
1535 RefreshRate(Option<u32>),
1536 /// Specifies which `ClientApi` to create the context for.
1537 ClientApi(ClientApiHint),
1538 /// Specifies the major client API version that the created context must be
1539 /// compatible with.
1540 ///
1541 /// Window creation will fail if the resulting OpenGL version is less than
1542 /// the one requested.
1543 ContextVersionMajor(u32),
1544 /// Specifies the minor client API version that the created context must be
1545 /// compatible with.
1546 ///
1547 /// Window creation will fail if the resulting OpenGL version is less than
1548 /// the one requested.
1549 ContextVersionMinor(u32),
1550 /// Specifies the client API version that the created context must be
1551 /// compatible with. This is the same as successive calls to `window_hint`
1552 /// function with the `ContextVersionMajor` and `ContextVersionMinor` hints.
1553 ///
1554 /// Window creation will fail if the resulting OpenGL version is less than
1555 /// the one requested.
1556 ///
1557 /// If `ContextVersion(1, 0)` is requested, _most_ drivers will provide the
1558 /// highest available context.
1559 ContextVersion(u32, u32),
1560 /// Specifies the `ContextRobustness` strategy to be used.
1561 ContextRobustness(ContextRobustnessHint),
1562 /// Specifies whether the OpenGL context should be forward-compatible, i.e.
1563 /// one where all functionality deprecated in the requested version of
1564 /// OpenGL is removed. This may only be used if the requested OpenGL version
1565 /// is 3.0 or above.
1566 ///
1567 /// If another client API is requested, this hint is ignored.
1568 OpenGlForwardCompat(bool),
1569 /// Specifies whether to create a debug OpenGL context, which may have
1570 /// additional error and performance issue reporting functionality.
1571 ///
1572 /// If another client API is requested, this hint is ignored.
1573 OpenGlDebugContext(bool),
1574 /// Specifies which OpenGL profile to create the context for. If requesting
1575 /// an OpenGL version below 3.2, `OpenGlAnyProfile` must be used.
1576 ///
1577 /// If another client API is requested, this hint is ignored.
1578 OpenGlProfile(OpenGlProfileHint),
1579 /// Specifies whether the window will be resizable by the user. Even if this
1580 /// is set to `false`, the window can still be resized using the
1581 /// `Window::set_size` function.
1582 ///
1583 /// This hint is ignored for fullscreen windows.
1584 Resizable(bool),
1585 /// Specifies whether the window will be visible on creation.
1586 ///
1587 /// This hint is ignored for fullscreen windows.
1588 Visible(bool),
1589 /// Specifies whether the window will have platform-specific decorations
1590 /// such as a border, a close widget, etc.
1591 ///
1592 /// This hint is ignored for full screen windows.
1593 Decorated(bool),
1594 /// Specifies whether the (full screen) window will automatically iconify
1595 /// and restore the previous video mode on input focus loss.
1596 ///
1597 /// This hint is ignored for windowed mode windows.
1598 AutoIconify(bool),
1599 /// Specifies whether the window will be floating above other regular
1600 /// windows, also called topmost or always-on-top.
1601 ///
1602 /// This hint is ignored for full screen windows.
1603 Floating(bool),
1604 /// Specifies whether the windowed mode window will be given input focus when created.
1605 ///
1606 /// This hint is ignored for full screen and initially hidden windows.
1607 Focused(bool),
1608 /// Specifies whether the OpenGL or OpenGL ES contexts do not emit errors,
1609 /// allowing for better performance in some situations.
1610 ContextNoError(bool),
1611 /// Specifies which context creation API to use to create the context.
1612 ContextCreationApi(ContextCreationApi),
1613 /// Specifies the behavior of the OpenGL pipeline when a context is transferred between threads
1614 ContextReleaseBehavior(ContextReleaseBehavior),
1615 /// Specifies whether the framebuffer should be double buffered.
1616 ///
1617 /// You nearly always want to use double buffering.
1618 ///
1619 /// Note that setting this to false will make `swap_buffers` do nothing useful,
1620 /// and your scene will have to be displayed some other way.
1621 DoubleBuffer(bool),
1622 /// Speficies whether the cursor should be centered over newly created full screen windows.
1623 ///
1624 /// This hint is ignored for windowed mode windows.
1625 CenterCursor(bool),
1626 /// Specifies whether the window framebuffer will be transparent.
1627 ///
1628 /// If enabled and supported by the system, the window framebuffer alpha channel will be used to
1629 /// combine the framebuffer with the background. This does not affect window decorations.
1630 TransparentFramebuffer(bool),
1631 /// Specifies whether the window will be given input focus when `Window::show` is called.
1632 FocusOnShow(bool),
1633 /// Specifies whether the window content area should be resized based on the monitor current scale
1634 /// of any monitor it is placed on.
1635 ///
1636 /// This includes the initial placement when the window is created.
1637 ScaleToMonitor(bool),
1638 /// Specifies whether to use full resolution framebuffers on Retina displays.
1639 ///
1640 /// This is ignored on platforms besides macOS.
1641 CocoaRetinaFramebuffer(bool),
1642 /// Specifies the UTF-8 encoded name to use for autosaving the window frame, or if empty disables
1643 /// frame autosaving for the window.
1644 ///
1645 /// This is ignored on platforms besides macOS.
1646 CocoaFrameName(Option<String>),
1647 /// Specifies whether to in participate in Automatic Graphics Switching, i.e. to allow the system
1648 /// to choose the integrated GPU for the OpenGL context and move it between GPUs if necessary or
1649 /// whether to force it to always run on the discrete GPU.
1650 ///
1651 /// Simpler programs and tools may want to enable this to save power, while games and other
1652 /// applications performing advanced rendering will want to leave it disabled.
1653 //
1654 // A bundled application that wishes to participate in Automatic Graphics Switching should also
1655 // declare this in its `Info.plist` by setting the `NSSupportsAutomaticGraphicsSwitching` key to
1656 // `true`.
1657 ///
1658 /// This only affects systems with both integrated and discrete GPUs. This is ignored on platforms
1659 /// besides macOS.
1660 CocoaGraphicsSwitching(bool),
1661 /// Specifies the desired ASCII-encoded class part of the ICCCM `WM_CLASS` window property.
1662 X11ClassName(Option<String>),
1663 /// Specifies the desired ASCII-encoded instance part of the ICCCM `WM_CLASS` window property.
1664 X11InstanceName(Option<String>),
1665 }
1666
1667 /// Client API tokens.
1668 #[repr(i32)]
1669 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
1670 pub enum ClientApiHint {
1671 NoApi = ffi::NO_API,
1672 OpenGl = ffi::OPENGL_API,
1673 OpenGlEs = ffi::OPENGL_ES_API,
1674 }
1675
1676 /// Context robustness tokens.
1677 #[repr(i32)]
1678 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
1679 pub enum ContextRobustnessHint {
1680 NoRobustness = ffi::NO_ROBUSTNESS,
1681 NoResetNotification = ffi::NO_RESET_NOTIFICATION,
1682 LoseContextOnReset = ffi::LOSE_CONTEXT_ON_RESET,
1683 }
1684
1685 /// OpenGL profile tokens.
1686 #[repr(i32)]
1687 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
1688 pub enum OpenGlProfileHint {
1689 Any = ffi::OPENGL_ANY_PROFILE,
1690 Core = ffi::OPENGL_CORE_PROFILE,
1691 Compat = ffi::OPENGL_COMPAT_PROFILE,
1692 }
1693
1694 /// Describes the mode of a window
1695 #[derive(Copy, Clone, Debug)]
1696 pub enum WindowMode<'a> {
1697 /// Full screen mode. Contains the monitor on which the window is displayed.
1698 FullScreen(&'a Monitor),
1699
1700 /// Windowed mode.
1701 Windowed,
1702 }
1703
1704 /// Private conversion methods for `glfw::WindowMode`
1705 impl<'a> WindowMode<'a> {
1706 /// Returns a pointer to a monitor if the window is fullscreen, otherwise
1707 /// it returns a null pointer (if it is in windowed mode).
to_ptr(&self) -> *mut ffi::GLFWmonitor1708 fn to_ptr(&self) -> *mut ffi::GLFWmonitor {
1709 match *self {
1710 WindowMode::FullScreen(ref monitor) => monitor.ptr,
1711 WindowMode::Windowed => ptr::null_mut(),
1712 }
1713 }
1714 }
1715
1716 bitflags! {
1717 #[doc = "Key modifiers (e.g., Shift, Control, Alt, Super)"]
1718 pub struct Modifiers: ::libc::c_int {
1719 const Shift = ::ffi::MOD_SHIFT;
1720 const Control = ::ffi::MOD_CONTROL;
1721 const Alt = ::ffi::MOD_ALT;
1722 const Super = ::ffi::MOD_SUPER;
1723 const CapsLock = ::ffi::MOD_CAPS_LOCK;
1724 const NumLock = ::ffi::MOD_NUM_LOCK;
1725 }
1726 }
1727
1728 /// Keyboard code returned by the OS
1729 pub type Scancode = c_int;
1730
1731 /// Window event messages.
1732 #[derive(Clone, PartialEq, PartialOrd, Debug)]
1733 pub enum WindowEvent {
1734 Pos(i32, i32),
1735 Size(i32, i32),
1736 Close,
1737 Refresh,
1738 Focus(bool),
1739 Iconify(bool),
1740 FramebufferSize(i32, i32),
1741 MouseButton(MouseButton, Action, Modifiers),
1742 CursorPos(f64, f64),
1743 CursorEnter(bool),
1744 Scroll(f64, f64),
1745 Key(Key, Scancode, Action, Modifiers),
1746 Char(char),
1747 CharModifiers(char, Modifiers),
1748 FileDrop(Vec<PathBuf>),
1749 Maximize(bool),
1750 ContentScale(f32, f32),
1751 }
1752
1753 /// Returns an iterator that yields until no more messages are contained in the
1754 /// `Receiver`'s queue. This is useful for event handling where the blocking
1755 /// behaviour of `Receiver::iter` is undesirable.
1756 ///
1757 /// # Example
1758 ///
1759 /// ~~~ignore
1760 /// for event in glfw::flush_messages(&events) {
1761 /// // handle event
1762 /// }
1763 /// ~~~
flush_messages<'a, Message: Send>(receiver: &'a Receiver<Message>) -> FlushedMessages<'a, Message>1764 pub fn flush_messages<'a, Message: Send>(receiver: &'a Receiver<Message>) -> FlushedMessages<'a, Message> {
1765 FlushedMessages(receiver)
1766 }
1767
1768 /// An iterator that yields until no more messages are contained in the
1769 /// `Receiver`'s queue.
1770 pub struct FlushedMessages<'a, Message: 'a + Send>(&'a Receiver<Message>);
1771
1772 unsafe impl<'a, Message: 'a + Send> Send for FlushedMessages<'a, Message> {
1773 }
1774
1775 impl<'a, Message: 'static + Send> Iterator for FlushedMessages<'a, Message> {
1776 type Item = Message;
1777
next(&mut self) -> Option<Message>1778 fn next(&mut self) -> Option<Message> {
1779 let FlushedMessages(receiver) = *self;
1780 match receiver.try_recv() {
1781 Ok(message) => Some(message),
1782 _ => None,
1783 }
1784 }
1785 }
1786
1787 /// A struct that wraps a `*GLFWwindow` handle.
1788 pub struct Window {
1789 ptr: *mut ffi::GLFWwindow,
1790 pub glfw: Glfw,
1791 pub is_shared: bool,
1792 /// A `Sender` that can be cloned out to child `RenderContext`s.
1793 drop_sender: Option<Sender<()>>,
1794 /// Once all child`RenderContext`s have been dropped, calling `try_recv()`
1795 /// on the `drop_receiver` will result in an `Err(std::comm::Disconnected)`,
1796 /// indicating that it is safe to drop the `Window`.
1797 drop_receiver: Receiver<()>,
1798 /// This is here to allow owning the current Cursor object instead
1799 /// of forcing the user to take care of its lifetime.
1800 current_cursor: Option<Cursor>
1801 }
1802
1803 macro_rules! set_window_callback {
1804 ($window:ident, $should_poll:expr, $ll_fn:ident, $callback:ident) => ({
1805 if $should_poll {
1806 unsafe { ffi::$ll_fn($window.ptr, Some(callbacks::$callback)); }
1807 } else {
1808 unsafe { ffi::$ll_fn($window.ptr, None); }
1809 }
1810 })
1811 }
1812
1813 impl Window {
1814 /// Returns the address of the specified client API or extension function if
1815 /// it is supported by the context associated with this Window. If this Window is not the
1816 /// current context, it will make it the current context.
1817 ///
1818 /// Wrapper for `glfwGetProcAddress`.
get_proc_address(&mut self, procname: &str) -> GLProc1819 pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
1820 if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
1821 self.make_current();
1822 }
1823
1824 self.glfw.get_proc_address_raw(procname)
1825 }
1826
1827 /// This function returns the address of the specified Vulkan core or extension function
1828 /// for the specified instance. If instance is set to NULL it can return any function
1829 /// exported from the Vulkan loader, including at least the following functions:
1830 ///
1831 /// * `vkEnumerateInstanceExtensionProperties`
1832 /// * `vkEnumerateInstanceLayerProperties`
1833 /// * `vkCreateInstance`
1834 /// * `vkGetInstanceProcAddr`
1835 ///
1836 /// If Vulkan is not available on the machine, this function returns `NULL`
1837 ///
1838 /// Wrapper for `glfwGetInstanceProcAddress`
1839 #[cfg(feature = "vulkan")]
get_instance_proc_address(&mut self, instance: VkInstance, procname: &str) -> VkProc1840 pub fn get_instance_proc_address(&mut self, instance: VkInstance, procname: &str) -> VkProc {
1841 self.glfw.get_instance_proc_address_raw(instance, procname)
1842 }
1843
1844 /// This function returns whether the specified queue family of the specified
1845 /// physical device supports presentation to the platform GLFW was built for.
1846 ///
1847 /// Wrapper for `glfwGetPhysicalDevicePresentationSupport`
1848 #[cfg(feature = "vulkan")]
get_physical_device_presentation_support(&self, instance: VkInstance, device: VkPhysicalDevice, queue_family: u32) -> bool1849 pub fn get_physical_device_presentation_support(&self, instance: VkInstance, device: VkPhysicalDevice, queue_family: u32) -> bool {
1850 self.glfw.get_physical_device_presentation_support_raw(instance, device, queue_family)
1851 }
1852
1853 /// Wrapper for `glfwCreateWindow`.
create_shared(&self, width: u32, height: u32, title: &str, mode: WindowMode) -> Option<(Window, Receiver<(f64, WindowEvent)>)>1854 pub fn create_shared(&self, width: u32, height: u32, title: &str, mode: WindowMode) -> Option<(Window, Receiver<(f64, WindowEvent)>)> {
1855 self.glfw.create_window_intern(width, height, title, mode, Some(self))
1856 }
1857
1858 /// Calling this method forces the destructor to be called, closing the
1859 /// window.
close(self)1860 pub fn close(self) {}
1861
1862 /// Returns a render context that can be shared between tasks, allowing
1863 /// for concurrent rendering.
render_context(&mut self) -> RenderContext1864 pub fn render_context(&mut self) -> RenderContext {
1865 RenderContext {
1866 ptr: self.ptr,
1867 // this will only be None after dropping so this is safe
1868 drop_sender: self.drop_sender.as_ref().unwrap().clone()
1869 }
1870 }
1871
1872 /// Wrapper for `glfwWindowShouldClose`.
should_close(&self) -> bool1873 pub fn should_close(&self) -> bool {
1874 unsafe { ffi::glfwWindowShouldClose(self.ptr) == ffi::TRUE }
1875 }
1876
1877 /// Wrapper for `glfwSetWindowShouldClose`.
set_should_close(&mut self, value: bool)1878 pub fn set_should_close(&mut self, value: bool) {
1879 unsafe { ffi::glfwSetWindowShouldClose(self.ptr, value as c_int) }
1880 }
1881
1882 /// Sets the title of the window.
1883 ///
1884 /// Wrapper for `glfwSetWindowTitle`.
set_title(&mut self, title: &str)1885 pub fn set_title(&mut self, title: &str) {
1886 unsafe {
1887 with_c_str(title, |title| {
1888 ffi::glfwSetWindowTitle(self.ptr, title);
1889 });
1890 }
1891 }
1892
1893 /// Wrapper for `glfwGetWindowPos`.
get_pos(&self) -> (i32, i32)1894 pub fn get_pos(&self) -> (i32, i32) {
1895 unsafe {
1896 let mut xpos = 0;
1897 let mut ypos = 0;
1898 ffi::glfwGetWindowPos(self.ptr, &mut xpos, &mut ypos);
1899 (xpos as i32, ypos as i32)
1900 }
1901 }
1902
1903 /// Wrapper for `glfwSetWindowPos`.
set_pos(&mut self, xpos: i32, ypos: i32)1904 pub fn set_pos(&mut self, xpos: i32, ypos: i32) {
1905 unsafe { ffi::glfwSetWindowPos(self.ptr, xpos as c_int, ypos as c_int); }
1906 }
1907
1908 /// Wrapper for `glfwGetWindowSize`.
get_size(&self) -> (i32, i32)1909 pub fn get_size(&self) -> (i32, i32) {
1910 unsafe {
1911 let mut width = 0;
1912 let mut height = 0;
1913 ffi::glfwGetWindowSize(self.ptr, &mut width, &mut height);
1914 (width as i32, height as i32)
1915 }
1916 }
1917
1918 /// Wrapper for `glfwSetWindowSize`.
set_size(&mut self, width: i32, height: i32)1919 pub fn set_size(&mut self, width: i32, height: i32) {
1920 unsafe { ffi::glfwSetWindowSize(self.ptr, width as c_int, height as c_int); }
1921 }
1922
1923 /// Wrapper for `glfwGetWindowFrameSize`
1924 ///
1925 /// Returns `(left, top, right, bottom)` edge window frame sizes, in screen coordinates.
get_frame_size(&self) -> (i32, i32, i32, i32)1926 pub fn get_frame_size(&self) -> (i32, i32, i32, i32) {
1927 let (mut left, mut top, mut right, mut bottom): (i32, i32, i32, i32) = (0, 0, 0, 0);
1928
1929 unsafe {
1930 ffi::glfwGetWindowFrameSize(self.ptr, &mut left as *mut c_int, &mut top as *mut c_int, &mut right as *mut c_int, &mut bottom as *mut c_int);
1931 }
1932
1933 (left, top, right, bottom)
1934 }
1935
1936 /// Wrapper for `glfwGetFramebufferSize`.
get_framebuffer_size(&self) -> (i32, i32)1937 pub fn get_framebuffer_size(&self) -> (i32, i32) {
1938 unsafe {
1939 let mut width = 0;
1940 let mut height = 0;
1941 ffi::glfwGetFramebufferSize(self.ptr, &mut width, &mut height);
1942 (width as i32, height as i32)
1943 }
1944 }
1945
1946 /// Wrapper for `glfwSetWindowAspectRatio`.
set_aspect_ratio(&mut self, numer: u32, denum: u32)1947 pub fn set_aspect_ratio(&mut self, numer: u32, denum: u32) {
1948 unsafe { ffi::glfwSetWindowAspectRatio(self.ptr, numer as c_int, denum as c_int) }
1949 }
1950
1951 /// Wrapper for `glfwSetWindowSizeLimits`.
set_size_limits(&mut self, minwidth: u32, minheight: u32, maxwidth: u32, maxheight: u32)1952 pub fn set_size_limits(&mut self, minwidth: u32, minheight: u32, maxwidth: u32, maxheight: u32) {
1953 unsafe { ffi::glfwSetWindowSizeLimits(self.ptr , minwidth as c_int, minheight as c_int, maxwidth as c_int, maxheight as c_int) }
1954 }
1955
1956 /// Wrapper for `glfwIconifyWindow`.
iconify(&mut self)1957 pub fn iconify(&mut self) {
1958 unsafe { ffi::glfwIconifyWindow(self.ptr); }
1959 }
1960
1961 /// Wrapper for `glfwRestoreWindow`.
restore(&mut self)1962 pub fn restore(&mut self) {
1963 unsafe { ffi::glfwRestoreWindow(self.ptr); }
1964 }
1965
1966 /// Wrapper for `glfwMaximizeWindow`
maximize(&mut self)1967 pub fn maximize(&mut self) {
1968 unsafe { ffi::glfwMaximizeWindow(self.ptr) }
1969 }
1970
1971 /// Wrapper for `glfwShowWindow`.
show(&mut self)1972 pub fn show(&mut self) {
1973 unsafe { ffi::glfwShowWindow(self.ptr); }
1974 }
1975
1976 /// Wrapper for `glfwHideWindow`.
hide(&mut self)1977 pub fn hide(&mut self) {
1978 unsafe { ffi::glfwHideWindow(self.ptr); }
1979 }
1980
1981 /// Returns whether the window is fullscreen or windowed.
1982 ///
1983 /// # Example
1984 ///
1985 /// ~~~ignore
1986 /// window.with_window_mode(|mode| {
1987 /// match mode {
1988 /// glfw::Windowed => println!("Windowed"),
1989 /// glfw::FullScreen(m) => println!("FullScreen({})", m.get_name()),
1990 /// }
1991 /// });
1992 /// ~~~
with_window_mode<T, F>(&self, f: F) -> T where F: Fn(WindowMode) -> T1993 pub fn with_window_mode<T, F>(&self, f: F) -> T where F: Fn(WindowMode) -> T {
1994 let ptr = unsafe { ffi::glfwGetWindowMonitor(self.ptr) };
1995 if ptr.is_null() {
1996 f(WindowMode::Windowed)
1997 } else {
1998 f(WindowMode::FullScreen(&Monitor {
1999 ptr: ptr
2000 }))
2001 }
2002 }
2003
2004 /// Returns whether the window is fullscreen or windowed.
2005 ///
2006 /// Variant that can accept an `FnMut` closure.
2007 ///
2008 /// # Example
2009 ///
2010 /// ~~~ignore
2011 /// window.with_window_mode(|mode| {
2012 /// match mode {
2013 /// glfw::Windowed => println!("Windowed"),
2014 /// glfw::FullScreen(m) => println!("FullScreen({})", m.get_name()),
2015 /// }
2016 /// });
2017 /// ~~~
with_window_mode_mut<T, F>(&self, mut f: F) -> T where F: FnMut(WindowMode) -> T2018 pub fn with_window_mode_mut<T, F>(&self, mut f: F) -> T where F: FnMut(WindowMode) -> T {
2019 let ptr = unsafe { ffi::glfwGetWindowMonitor(self.ptr) };
2020 if ptr.is_null() {
2021 f(WindowMode::Windowed)
2022 } else {
2023 f(WindowMode::FullScreen(&Monitor {
2024 ptr: ptr
2025 }))
2026 }
2027 }
2028
2029 /// Wrapper for `glfwSetWindowMonitor`
set_monitor(&mut self, mode: WindowMode, xpos: i32, ypos: i32, width: u32, height: u32, refresh_rate: Option<u32>)2030 pub fn set_monitor(&mut self, mode: WindowMode, xpos: i32, ypos: i32, width: u32, height: u32, refresh_rate: Option<u32>) {
2031 let monitor_ptr = if let WindowMode::FullScreen(ref monitor) = mode { monitor.ptr } else { ptr::null_mut() };
2032
2033 unsafe {
2034 ffi::glfwSetWindowMonitor(self.ptr, monitor_ptr, xpos as c_int, ypos as c_int, width as c_int, height as c_int, match refresh_rate {
2035 Some(value) => value as c_int,
2036 None => ffi::DONT_CARE
2037 })
2038 }
2039 }
2040
2041 /// Wrapper for `glfwFocusWindow`
2042 ///
2043 /// It is NOT recommended to use this function, as it steals focus from other applications
2044 /// and can be extremely disruptive to the user.
focus(&mut self)2045 pub fn focus(&mut self) {
2046 unsafe { ffi::glfwFocusWindow(self.ptr) }
2047 }
2048
2049 /// Wrapper for `glfwGetWindowAttrib` called with `FOCUSED`.
is_focused(&self) -> bool2050 pub fn is_focused(&self) -> bool {
2051 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FOCUSED) == ffi::TRUE }
2052 }
2053
2054 /// Wrapper for `glfwGetWindowAttrib` called with `ICONIFIED`.
is_iconified(&self) -> bool2055 pub fn is_iconified(&self) -> bool {
2056 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::ICONIFIED) == ffi::TRUE }
2057 }
2058
2059 /// Wrapper for `glfwGetWindowattrib` called with `MAXIMIZED`.
is_maximized(&self) -> bool2060 pub fn is_maximized(&self) -> bool {
2061 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::MAXIMIZED) == ffi::TRUE }
2062 }
2063
2064 /// Wrapper for `glfwGetWindowAttrib` called with `CLIENT_API`.
get_client_api(&self) -> c_int2065 pub fn get_client_api(&self) -> c_int {
2066 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::CLIENT_API) }
2067 }
2068
2069 /// Wrapper for `glfwGetWindowAttrib` called with
2070 /// `CONTEXT_VERSION_MAJOR`, `CONTEXT_VERSION_MINOR` and `CONTEXT_REVISION`.
2071 ///
2072 /// # Returns
2073 ///
2074 /// The client API version of the window's context in a version struct.
get_context_version(&self) -> Version2075 pub fn get_context_version(&self) -> Version {
2076 unsafe {
2077 Version {
2078 major: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_VERSION_MAJOR) as u64,
2079 minor: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_VERSION_MINOR) as u64,
2080 patch: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_REVISION) as u64,
2081 pre: Vec::new(),
2082 build: Vec::new(),
2083 }
2084 }
2085 }
2086
2087 /// Wrapper for `glfwGetWindowAttrib` called with `CONTEXT_ROBUSTNESS`.
get_context_robustness(&self) -> c_int2088 pub fn get_context_robustness(&self) -> c_int {
2089 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_ROBUSTNESS) }
2090 }
2091
2092 /// Wrapper for `glfwGetWindowAttrib` called with `OPENGL_FORWARD_COMPAT`.
is_opengl_forward_compat(&self) -> bool2093 pub fn is_opengl_forward_compat(&self) -> bool {
2094 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_FORWARD_COMPAT) == ffi::TRUE }
2095 }
2096
2097 /// Wrapper for `glfwGetWindowAttrib` called with `OPENGL_DEBUG_CONTEXT`.
is_opengl_debug_context(&self) -> bool2098 pub fn is_opengl_debug_context(&self) -> bool {
2099 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_DEBUG_CONTEXT) == ffi::TRUE }
2100 }
2101
2102 /// Wrapper for `glfwGetWindowAttrib` called with `OPENGL_PROFILE`.
get_opengl_profile(&self) -> c_int2103 pub fn get_opengl_profile(&self) -> c_int {
2104 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_PROFILE) }
2105 }
2106
2107 /// Wrapper for `glfwGetWindowAttrib` called with `RESIZABLE`.
is_resizable(&self) -> bool2108 pub fn is_resizable(&self) -> bool {
2109 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::RESIZABLE) == ffi::TRUE }
2110 }
2111
2112 /// Wrapper for `glfwSetWindowAttrib` called with `RESIZABLE`.
set_resizable(&mut self, resizable: bool)2113 pub fn set_resizable(&mut self, resizable: bool) {
2114 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::RESIZABLE, resizable as c_int) }
2115 }
2116
2117 /// Wrapper for `glfwGetWindowAttrib` called with `VISIBLE`.
is_visible(&self) -> bool2118 pub fn is_visible(&self) -> bool {
2119 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::VISIBLE) == ffi::TRUE }
2120 }
2121
2122 /// Wrapper for `glfwGetWindowAttrib` called with `DECORATED`.
is_decorated(&self) -> bool2123 pub fn is_decorated(&self) -> bool {
2124 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::DECORATED) == ffi::TRUE }
2125 }
2126
2127 /// Wrapper for `glfwSetWindowAttrib` called with `DECORATED`.
set_decorated(&mut self, decorated: bool)2128 pub fn set_decorated(&mut self, decorated: bool) {
2129 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::DECORATED, decorated as c_int) }
2130 }
2131
2132 /// Wrapper for `glfwGetWindowAttrib` called with `AUTO_ICONIFY`.
is_auto_iconify(&self) -> bool2133 pub fn is_auto_iconify(&self) -> bool {
2134 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::AUTO_ICONIFY) == ffi::TRUE }
2135 }
2136
2137 /// Wrapper for `glfwSetWindowAttrib` called with `AUTO_ICONIFY`.
set_auto_iconify(&mut self, auto_iconify: bool)2138 pub fn set_auto_iconify(&mut self, auto_iconify: bool) {
2139 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::AUTO_ICONIFY, auto_iconify as c_int) }
2140 }
2141
2142 /// Wrapper for `glfwGetWindowAttrib` called with `FLOATING`.
is_floating(&self) -> bool2143 pub fn is_floating(&self) -> bool {
2144 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FLOATING) == ffi::TRUE }
2145 }
2146
2147 /// Wrapper for `glfwSetWindowAttrib` called with `FLOATING`.
set_floating(&mut self, floating: bool)2148 pub fn set_floating(&mut self, floating: bool) {
2149 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::FLOATING, floating as c_int) }
2150 }
2151
2152 /// Wrapper for `glfwGetWindowAttrib` called with `TRANSPARENT_FRAMEBUFFER`.
is_framebuffer_transparent(&self) -> bool2153 pub fn is_framebuffer_transparent(&self) -> bool {
2154 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::TRANSPARENT_FRAMEBUFFER) == ffi::TRUE }
2155 }
2156
2157 /// Wrapper for `glfwGetWindowAttrib` called with `FOCUS_ON_SHOW`.
is_focus_on_show(&self) -> bool2158 pub fn is_focus_on_show(&self) -> bool {
2159 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FOCUS_ON_SHOW) == ffi::TRUE }
2160 }
2161
2162 /// Wrapper for `glfwSetWindowAttrib` called with `FOCUS_ON_SHOW`.
set_focus_on_show(&mut self, focus_on_show: bool)2163 pub fn set_focus_on_show(&mut self, focus_on_show: bool) {
2164 unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::FOCUS_ON_SHOW, focus_on_show as c_int) }
2165 }
2166
2167 /// Wrapper for `glfwGetWindowAttrib` called with `HOVERED`.
is_hovered(&self) -> bool2168 pub fn is_hovered(&self) -> bool {
2169 unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::HOVERED) == ffi::TRUE }
2170 }
2171
2172 /// Wrapper for `glfwSetWindowPosCallback`.
set_pos_polling(&mut self, should_poll: bool)2173 pub fn set_pos_polling(&mut self, should_poll: bool) {
2174 set_window_callback!(self, should_poll, glfwSetWindowPosCallback, window_pos_callback);
2175 }
2176
2177 /// Starts or stops polling for all available events
set_all_polling(&mut self, should_poll: bool)2178 pub fn set_all_polling(&mut self, should_poll: bool) {
2179 self.set_pos_polling(should_poll);
2180 self.set_size_polling(should_poll);
2181 self.set_close_polling(should_poll);
2182 self.set_refresh_polling(should_poll);
2183 self.set_focus_polling(should_poll);
2184 self.set_iconify_polling(should_poll);
2185 self.set_framebuffer_size_polling(should_poll);
2186 self.set_key_polling(should_poll);
2187 self.set_char_polling(should_poll);
2188 self.set_char_mods_polling(should_poll);
2189 self.set_mouse_button_polling(should_poll);
2190 self.set_cursor_pos_polling(should_poll);
2191 self.set_cursor_enter_polling(should_poll);
2192 self.set_scroll_polling(should_poll);
2193 self.set_drag_and_drop_polling(should_poll);
2194 self.set_maximize_polling(should_poll);
2195 self.set_content_scale_polling(should_poll);
2196 }
2197
2198 /// Wrapper for `glfwSetWindowSizeCallback`.
set_size_polling(&mut self, should_poll: bool)2199 pub fn set_size_polling(&mut self, should_poll: bool) {
2200 set_window_callback!(self, should_poll, glfwSetWindowSizeCallback, window_size_callback);
2201 }
2202
2203 /// Wrapper for `glfwSetWindowCloseCallback`.
set_close_polling(&mut self, should_poll: bool)2204 pub fn set_close_polling(&mut self, should_poll: bool) {
2205 set_window_callback!(self, should_poll, glfwSetWindowCloseCallback, window_close_callback);
2206 }
2207
2208 /// Wrapper for `glfwSetWindowRefreshCallback`.
set_refresh_polling(&mut self, should_poll: bool)2209 pub fn set_refresh_polling(&mut self, should_poll: bool) {
2210 set_window_callback!(self, should_poll, glfwSetWindowRefreshCallback, window_refresh_callback);
2211 }
2212
2213 /// Wrapper for `glfwSetWindowFocusCallback`.
set_focus_polling(&mut self, should_poll: bool)2214 pub fn set_focus_polling(&mut self, should_poll: bool) {
2215 set_window_callback!(self, should_poll, glfwSetWindowFocusCallback, window_focus_callback);
2216 }
2217
2218 /// Wrapper for `glfwSetWindowIconifyCallback`.
set_iconify_polling(&mut self, should_poll: bool)2219 pub fn set_iconify_polling(&mut self, should_poll: bool) {
2220 set_window_callback!(self, should_poll, glfwSetWindowIconifyCallback, window_iconify_callback);
2221 }
2222
2223 /// Wrapper for `glfwSetFramebufferSizeCallback`.
set_framebuffer_size_polling(&mut self, should_poll: bool)2224 pub fn set_framebuffer_size_polling(&mut self, should_poll: bool) {
2225 set_window_callback!(self, should_poll, glfwSetFramebufferSizeCallback, framebuffer_size_callback);
2226 }
2227
2228 /// Wrapper for `glfwSetDropCallback`.
set_drag_and_drop_polling(&mut self, should_poll: bool)2229 pub fn set_drag_and_drop_polling(&mut self, should_poll: bool) {
2230 set_window_callback!(self, should_poll, glfwSetDropCallback, drop_callback);
2231 }
2232
2233 /// Wrapper for `glfwSetWindowMaximizeCallback`.
set_maximize_polling(&mut self, should_poll: bool)2234 pub fn set_maximize_polling(&mut self, should_poll: bool) {
2235 set_window_callback!(self, should_poll, glfwSetWindowMaximizeCallback, window_maximize_callback);
2236 }
2237
2238 /// Wrapper for `glfwSetWindowContentScaleCallback`.
set_content_scale_polling(&mut self, should_poll: bool)2239 pub fn set_content_scale_polling(&mut self, should_poll: bool) {
2240 set_window_callback!(self, should_poll, glfwSetWindowContentScaleCallback, window_content_scale_callback);
2241 }
2242
2243 /// Wrapper for `glfwGetInputMode` called with `CURSOR`.
get_cursor_mode(&self) -> CursorMode2244 pub fn get_cursor_mode(&self) -> CursorMode {
2245 unsafe { mem::transmute(ffi::glfwGetInputMode(self.ptr, ffi::CURSOR)) }
2246 }
2247
2248 /// Wrapper for `glfwSetInputMode` called with `CURSOR`.
set_cursor_mode(&mut self, mode: CursorMode)2249 pub fn set_cursor_mode(&mut self, mode: CursorMode) {
2250 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::CURSOR, mode as c_int); }
2251 }
2252
2253 /// Wrapper for `glfwSetCursor` using `Cursor`
2254 ///
2255 /// The window will take ownership of the cursor, and will not Drop it
2256 /// until it is replaced or the window itself is destroyed.
2257 ///
2258 /// Returns the previously set Cursor or None if no cursor was set.
set_cursor(&mut self, cursor: Option<Cursor>) -> Option<Cursor>2259 pub fn set_cursor(&mut self, cursor: Option<Cursor>) -> Option<Cursor> {
2260 let previous = mem::replace(&mut self.current_cursor, cursor);
2261
2262 unsafe {
2263 ffi::glfwSetCursor(self.ptr, match self.current_cursor {
2264 Some(ref cursor) => cursor.ptr,
2265 None => ptr::null_mut()
2266 })
2267 }
2268
2269 previous
2270 }
2271
2272 /// Sets the window icon from the given images by called `glfwSetWindowIcon`
2273 ///
2274 /// Multiple images can be specified for allowing the OS to choose the best size where necessary.
2275 ///
2276 /// Example:
2277 ///
2278 /// ```ignore
2279 ///if let DynamicImage::ImageRgba8(icon) = image::open("examples/icon.png").unwrap() {
2280 /// window.set_icon(vec![
2281 /// imageops::resize(&icon, 16, 16, image::imageops::Lanczos3),
2282 /// imageops::resize(&icon, 32, 32, image::imageops::Lanczos3),
2283 /// imageops::resize(&icon, 48, 48, image::imageops::Lanczos3)
2284 /// ]);
2285 ///}
2286 /// ```
2287 #[cfg(feature = "image")]
set_icon(&mut self, images: Vec<image::RgbaImage>)2288 pub fn set_icon(&mut self, images: Vec<image::RgbaImage>) {
2289 // When the images are turned into Vecs, the lifetimes of them go into the Vec lifetime
2290 // So they need to be kept until the function ends.
2291 let image_data : Vec<(Vec<_>, u32, u32)> = images.into_iter().map(|image| {
2292 let (width, height) = image.dimensions();
2293
2294 (image.into_vec(), width, height)
2295 }).collect();
2296
2297 let glfw_images: Vec<ffi::GLFWimage> = image_data.iter().map(|ref data| {
2298 ffi::GLFWimage {
2299 width: data.1 as c_int,
2300 height: data.2 as c_int,
2301 pixels: data.0.as_ptr() as *const c_uchar
2302 }
2303 }).collect();
2304
2305 unsafe {
2306 ffi::glfwSetWindowIcon(self.ptr, glfw_images.len() as c_int, glfw_images.as_ptr() as *const ffi::GLFWimage)
2307 }
2308 }
2309
2310 /// Sets the window icon via `glfwSetWindowIcon` from a set a set of vectors
2311 /// containing pixels in RGBA format (one pixel per 32-bit integer)
set_icon_from_pixels(&mut self, images: Vec<PixelImage>)2312 pub fn set_icon_from_pixels(&mut self, images: Vec<PixelImage>) {
2313 let glfw_images: Vec<ffi::GLFWimage> = images.iter().map(|image: &PixelImage| {
2314 ffi::GLFWimage {
2315 width: image.width as c_int,
2316 height: image.height as c_int,
2317 pixels: image.pixels.as_ptr() as *const c_uchar
2318 }
2319 }).collect();
2320
2321 unsafe {
2322 ffi::glfwSetWindowIcon(self.ptr, glfw_images.len() as c_int, glfw_images.as_ptr() as *const ffi::GLFWimage)
2323 }
2324 }
2325
2326 /// Wrapper for `glfwGetInputMode` called with `STICKY_KEYS`.
has_sticky_keys(&self) -> bool2327 pub fn has_sticky_keys(&self) -> bool {
2328 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::STICKY_KEYS) == ffi::TRUE }
2329 }
2330
2331 /// Wrapper for `glfwSetInputMode` called with `STICKY_KEYS`.
set_sticky_keys(&mut self, value: bool)2332 pub fn set_sticky_keys(&mut self, value: bool) {
2333 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::STICKY_KEYS, value as c_int); }
2334 }
2335
2336 /// Wrapper for `glfwGetInputMode` called with `STICKY_MOUSE_BUTTONS`.
has_sticky_mouse_buttons(&self) -> bool2337 pub fn has_sticky_mouse_buttons(&self) -> bool {
2338 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::STICKY_MOUSE_BUTTONS) == ffi::TRUE }
2339 }
2340
2341 /// Wrapper for `glfwSetInputMode` called with `STICKY_MOUSE_BUTTONS`.
set_sticky_mouse_buttons(&mut self, value: bool)2342 pub fn set_sticky_mouse_buttons(&mut self, value: bool) {
2343 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::STICKY_MOUSE_BUTTONS, value as c_int); }
2344 }
2345
2346 /// Wrapper for `glfwGetInputMode` called with `LOCK_KEY_MODS`
does_store_lock_key_mods(&self) -> bool2347 pub fn does_store_lock_key_mods(&self) -> bool {
2348 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::LOCK_KEY_MODS) == ffi::TRUE }
2349 }
2350
2351 /// Wrapper for `glfwSetInputMode` called with `LOCK_KEY_MODS`
set_store_lock_key_mods(&mut self, value: bool)2352 pub fn set_store_lock_key_mods(&mut self, value: bool) {
2353 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::LOCK_KEY_MODS, value as c_int) }
2354 }
2355
2356 /// Wrapper for `glfwGetInputMode` called with `RAW_MOUSE_MOTION`
uses_raw_mouse_motion(&self) -> bool2357 pub fn uses_raw_mouse_motion(&self) -> bool {
2358 unsafe { ffi::glfwGetInputMode(self.ptr, ffi::RAW_MOUSE_MOTION) == ffi::TRUE }
2359 }
2360
2361 /// Wrapper for `glfwSetInputMode` called with `RAW_MOUSE_MOTION`
set_raw_mouse_motion(&mut self, value: bool)2362 pub fn set_raw_mouse_motion(&mut self, value: bool) {
2363 unsafe { ffi::glfwSetInputMode(self.ptr, ffi::RAW_MOUSE_MOTION, value as c_int) }
2364 }
2365
2366 /// Wrapper for `glfwGetKey`.
get_key(&self, key: Key) -> Action2367 pub fn get_key(&self, key: Key) -> Action {
2368 unsafe { mem::transmute(ffi::glfwGetKey(self.ptr, key as c_int)) }
2369 }
2370
2371 /// Wrapper for `glfwGetMouseButton`.
get_mouse_button(&self, button: MouseButton) -> Action2372 pub fn get_mouse_button(&self, button: MouseButton) -> Action {
2373 unsafe { mem::transmute(ffi::glfwGetMouseButton(self.ptr, button as c_int)) }
2374 }
2375
2376 /// Wrapper for `glfwGetCursorPos`.
get_cursor_pos(&self) -> (f64, f64)2377 pub fn get_cursor_pos(&self) -> (f64, f64) {
2378 unsafe {
2379 let mut xpos = 0.0;
2380 let mut ypos = 0.0;
2381 ffi::glfwGetCursorPos(self.ptr, &mut xpos, &mut ypos);
2382 (xpos as f64, ypos as f64)
2383 }
2384 }
2385
2386 /// Wrapper for `glfwSetCursorPos`.
set_cursor_pos(&mut self, xpos: f64, ypos: f64)2387 pub fn set_cursor_pos(&mut self, xpos: f64, ypos: f64) {
2388 unsafe { ffi::glfwSetCursorPos(self.ptr, xpos as c_double, ypos as c_double); }
2389 }
2390
2391 /// Wrapper for `glfwSetKeyCallback`.
set_key_polling(&mut self, should_poll: bool)2392 pub fn set_key_polling(&mut self, should_poll: bool) {
2393 set_window_callback!(self, should_poll, glfwSetKeyCallback, key_callback);
2394 }
2395
2396 /// Wrapper for `glfwSetCharCallback`.
set_char_polling(&mut self, should_poll: bool)2397 pub fn set_char_polling(&mut self, should_poll: bool) {
2398 set_window_callback!(self, should_poll, glfwSetCharCallback, char_callback);
2399 }
2400
2401 /// Wrapper for `glfwSetCharModsCallback`
set_char_mods_polling(&mut self, should_poll: bool)2402 pub fn set_char_mods_polling(&mut self, should_poll: bool) {
2403 set_window_callback!(self, should_poll, glfwSetCharModsCallback, char_mods_callback);
2404 }
2405
2406 /// Wrapper for `glfwSetMouseButtonCallback`.
set_mouse_button_polling(&mut self, should_poll: bool)2407 pub fn set_mouse_button_polling(&mut self, should_poll: bool) {
2408 set_window_callback!(self, should_poll, glfwSetMouseButtonCallback, mouse_button_callback);
2409 }
2410
2411 /// Wrapper for `glfwSetCursorPosCallback`.
set_cursor_pos_polling(&mut self, should_poll: bool)2412 pub fn set_cursor_pos_polling(&mut self, should_poll: bool) {
2413 set_window_callback!(self, should_poll, glfwSetCursorPosCallback, cursor_pos_callback);
2414 }
2415
2416 /// Wrapper for `glfwSetCursorEnterCallback`.
set_cursor_enter_polling(&mut self, should_poll: bool)2417 pub fn set_cursor_enter_polling(&mut self, should_poll: bool) {
2418 set_window_callback!(self, should_poll, glfwSetCursorEnterCallback, cursor_enter_callback);
2419 }
2420
2421 /// Wrapper for `glfwSetScrollCallback`.
set_scroll_polling(&mut self, should_poll: bool)2422 pub fn set_scroll_polling(&mut self, should_poll: bool) {
2423 set_window_callback!(self, should_poll, glfwSetScrollCallback, scroll_callback);
2424 }
2425
2426 /// Wrapper for `glfwGetClipboardString`.
set_clipboard_string(&mut self, string: &str)2427 pub fn set_clipboard_string(&mut self, string: &str) {
2428 unsafe {
2429 with_c_str(string, |string| {
2430 ffi::glfwSetClipboardString(self.ptr, string);
2431 });
2432 }
2433 }
2434
2435 /// Wrapper for `glfwGetClipboardString`.
get_clipboard_string(&self) -> Option<String>2436 pub fn get_clipboard_string(&self) -> Option<String> {
2437 unsafe { string_from_nullable_c_str(ffi::glfwGetClipboardString(self.ptr)) }
2438 }
2439
2440 /// Wrapper for 'glfwGetWindowOpacity'.
get_opacity(&self) -> f322441 pub fn get_opacity(&self) -> f32 {
2442 unsafe { ffi::glfwGetWindowOpacity(self.ptr) }
2443 }
2444
2445 /// Wrapper for 'glfwSetWindowOpacity'.
set_opacity(&mut self, opacity: f32)2446 pub fn set_opacity(&mut self, opacity: f32) {
2447 unsafe { ffi::glfwSetWindowOpacity(self.ptr, opacity) }
2448 }
2449
2450 /// Wrapper for `glfwRequestWindowAttention`.
request_attention(&mut self)2451 pub fn request_attention(&mut self) {
2452 unsafe { ffi::glfwRequestWindowAttention(self.ptr) }
2453 }
2454
2455 /// Wrapper for `glfwGetWindowContentScale`.
get_content_scale(&self) -> (f32, f32)2456 pub fn get_content_scale(&self) -> (f32, f32) {
2457 unsafe {
2458 let mut xscale = 0.0_f32;
2459 let mut yscale = 0.0_f32;
2460 ffi::glfwGetWindowContentScale(self.ptr, &mut xscale, &mut yscale);
2461 (xscale, yscale)
2462 }
2463 }
2464
2465 /// Wrapper for `glfwGetWin32Window`
2466 #[cfg(target_os="windows")]
get_win32_window(&self) -> *mut c_void2467 pub fn get_win32_window(&self) -> *mut c_void {
2468 unsafe { ffi::glfwGetWin32Window(self.ptr) }
2469 }
2470
2471 /// Wrapper for `glfwGetWGLContext`
2472 #[cfg(target_os="windows")]
get_wgl_context(&self) -> *mut c_void2473 pub fn get_wgl_context(&self) -> *mut c_void {
2474 unsafe { ffi::glfwGetWGLContext(self.ptr) }
2475 }
2476
2477 /// Wrapper for `glfwGetCocoaWindow`
2478 #[cfg(target_os="macos")]
get_cocoa_window(&self) -> *mut c_void2479 pub fn get_cocoa_window(&self) -> *mut c_void {
2480 unsafe { ffi::glfwGetCocoaWindow(self.ptr) }
2481 }
2482
2483 /// Wrapper for `glfwGetNSGLContext`
2484 #[cfg(target_os="macos")]
get_nsgl_context(&self) -> *mut c_void2485 pub fn get_nsgl_context(&self) -> *mut c_void {
2486 unsafe { ffi::glfwGetNSGLContext(self.ptr) }
2487 }
2488
2489 /// Wrapper for `glfwGetX11Window`
2490 #[cfg(target_os="linux")]
get_x11_window(&self) -> *mut c_void2491 pub fn get_x11_window(&self) -> *mut c_void {
2492 unsafe { ffi::glfwGetX11Window(self.ptr) }
2493 }
2494
2495 /// Wrapper for `glfwGetGLXContext`
2496 #[cfg(target_os="linux")]
get_glx_context(&self) -> *mut c_void2497 pub fn get_glx_context(&self) -> *mut c_void {
2498 unsafe { ffi::glfwGetGLXContext(self.ptr) }
2499 }
2500 }
2501
2502 impl Drop for Window {
2503 /// Closes the window and performs the necessary cleanups. This will block
2504 /// until all associated `RenderContext`s were also dropped, and emit a
2505 /// `debug!` message to that effect.
2506 ///
2507 /// Wrapper for `glfwDestroyWindow`.
drop(&mut self)2508 fn drop(&mut self) {
2509 drop(self.drop_sender.take());
2510
2511 // Check if all senders from the child `RenderContext`s have hung up.
2512 if self.drop_receiver.try_recv() != Err(std::sync::mpsc::TryRecvError::Disconnected) {
2513 debug!("Attempted to drop a Window before the `RenderContext` was dropped.");
2514 debug!("Blocking until the `RenderContext` was dropped.");
2515 let _ = self.drop_receiver.recv();
2516 }
2517
2518 if !self.ptr.is_null() {
2519 unsafe {
2520 let _: Box<Sender<(f64, WindowEvent)>> = mem::transmute(ffi::glfwGetWindowUserPointer(self.ptr));
2521 }
2522 }
2523
2524 if !self.is_shared {
2525 unsafe { ffi::glfwDestroyWindow(self.ptr); }
2526 }
2527 }
2528 }
2529
2530 /// A rendering context that can be shared between tasks.
2531 pub struct RenderContext {
2532 ptr: *mut ffi::GLFWwindow,
2533 /// As long as this sender is alive, it is not safe to drop the parent
2534 /// `Window`.
2535 #[allow(dead_code)]
2536 drop_sender: Sender<()>,
2537 }
2538
2539 unsafe impl Send for RenderContext {}
2540
2541 /// Methods common to renderable contexts
2542 pub trait Context {
2543 /// Returns the pointer to the underlying `GLFWwindow`.
window_ptr(&self) -> *mut ffi::GLFWwindow2544 fn window_ptr(&self) -> *mut ffi::GLFWwindow;
2545
2546 /// Returns the unique identifier for this window.
window_id(&self) -> WindowId2547 fn window_id(&self) -> WindowId {
2548 self.window_ptr() as WindowId
2549 }
2550
2551 /// Swaps the front and back buffers of the window. If the swap interval is
2552 /// greater than zero, the GPU driver waits the specified number of screen
2553 /// updates before swapping the buffers.
2554 ///
2555 /// Wrapper for `glfwSwapBuffers`.
swap_buffers(&mut self)2556 fn swap_buffers(&mut self) {
2557 let ptr = self.window_ptr();
2558 unsafe { ffi::glfwSwapBuffers(ptr); }
2559 }
2560
2561 /// Returns `true` if the window is the current context.
is_current(&self) -> bool2562 fn is_current(&self) -> bool {
2563 self.window_ptr() == unsafe { ffi::glfwGetCurrentContext() }
2564 }
2565
2566 /// Wrapper for `glfwMakeContextCurrent`
make_current(&mut self)2567 fn make_current(&mut self) {
2568 let ptr = self.window_ptr();
2569 unsafe { ffi::glfwMakeContextCurrent(ptr); }
2570 }
2571
2572 /// Wrapper for `glfwWindowShouldClose`.
should_close(&self) -> bool2573 fn should_close(&self) -> bool {
2574 let ptr = self.window_ptr();
2575 unsafe { ffi::glfwWindowShouldClose(ptr) == ffi::TRUE }
2576 }
2577
2578 /// Wrapper for `glfwSetWindowShouldClose`.
set_should_close(&mut self, value: bool)2579 fn set_should_close(&mut self, value: bool) {
2580 let ptr = self.window_ptr();
2581 unsafe { ffi::glfwSetWindowShouldClose(ptr, value as c_int); }
2582 }
2583
2584 /// Wrapper for `glfwPostEmptyEvent`.
post_empty_event(&self)2585 fn post_empty_event(&self) {
2586 unsafe { ffi::glfwPostEmptyEvent() }
2587 }
2588 }
2589
2590 impl Context for Window {
window_ptr(&self) -> *mut ffi::GLFWwindow2591 fn window_ptr(&self) -> *mut ffi::GLFWwindow { self.ptr }
2592 }
2593
2594 impl Context for RenderContext {
window_ptr(&self) -> *mut ffi::GLFWwindow2595 fn window_ptr(&self) -> *mut ffi::GLFWwindow { self.ptr }
2596 }
2597
2598 unsafe impl HasRawWindowHandle for Window {
raw_window_handle(&self) -> RawWindowHandle2599 fn raw_window_handle(&self) -> RawWindowHandle {
2600 raw_window_handle(self)
2601 }
2602 }
2603
2604 unsafe impl HasRawWindowHandle for RenderContext {
raw_window_handle(&self) -> RawWindowHandle2605 fn raw_window_handle(&self) -> RawWindowHandle {
2606 raw_window_handle(self)
2607 }
2608 }
2609
raw_window_handle<C: Context>(context: &C) -> RawWindowHandle2610 fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
2611 #[cfg(target_family = "windows")]
2612 {
2613 use raw_window_handle::windows::WindowsHandle;
2614 let hwnd = unsafe {
2615 ffi::glfwGetWin32Window(context.window_ptr())
2616 };
2617 RawWindowHandle::Windows(WindowsHandle {
2618 hwnd,
2619 ..WindowsHandle::empty()
2620 })
2621 }
2622
2623 #[cfg(any(target_os="linux", target_os="freebsd", target_os="dragonfly"))]
2624 {
2625 use raw_window_handle::unix::XlibHandle;
2626 let (window, display) = unsafe {
2627 let window = ffi::glfwGetX11Window(context.window_ptr());
2628 let display = ffi::glfwGetX11Display();
2629 (window as std::os::raw::c_ulong, display)
2630 };
2631 RawWindowHandle::Xlib(XlibHandle {
2632 window,
2633 display,
2634 ..XlibHandle::empty()
2635 })
2636 }
2637
2638 #[cfg(target_os="macos")]
2639 {
2640 use raw_window_handle::macos::MacOSHandle;
2641 let (ns_window, ns_view) = unsafe {
2642 let ns_window: *mut objc::runtime::Object = ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _;
2643 let ns_view: *mut objc::runtime::Object = objc::msg_send![ns_window, contentView];
2644 assert_ne!(ns_view, std::ptr::null_mut());
2645 (ns_window as *mut std::ffi::c_void, ns_view as *mut std::ffi::c_void)
2646 };
2647 RawWindowHandle::MacOS(MacOSHandle {
2648 ns_window,
2649 ns_view,
2650 ..MacOSHandle::empty()
2651 })
2652 }
2653 }
2654
2655 /// Wrapper for `glfwMakeContextCurrent`.
make_context_current(context: Option<&dyn Context>)2656 pub fn make_context_current(context: Option<&dyn Context>) {
2657 match context {
2658 Some(ctx) => unsafe { ffi::glfwMakeContextCurrent(ctx.window_ptr()) },
2659 None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
2660 }
2661 }
2662
2663 /// Joystick identifier tokens.
2664 #[repr(i32)]
2665 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2666 pub enum JoystickId {
2667 Joystick1 = ffi::JOYSTICK_1,
2668 Joystick2 = ffi::JOYSTICK_2,
2669 Joystick3 = ffi::JOYSTICK_3,
2670 Joystick4 = ffi::JOYSTICK_4,
2671 Joystick5 = ffi::JOYSTICK_5,
2672 Joystick6 = ffi::JOYSTICK_6,
2673 Joystick7 = ffi::JOYSTICK_7,
2674 Joystick8 = ffi::JOYSTICK_8,
2675 Joystick9 = ffi::JOYSTICK_9,
2676 Joystick10 = ffi::JOYSTICK_10,
2677 Joystick11 = ffi::JOYSTICK_11,
2678 Joystick12 = ffi::JOYSTICK_12,
2679 Joystick13 = ffi::JOYSTICK_13,
2680 Joystick14 = ffi::JOYSTICK_14,
2681 Joystick15 = ffi::JOYSTICK_15,
2682 Joystick16 = ffi::JOYSTICK_16,
2683 }
2684
2685 impl JoystickId {
2686 /// Converts from `i32`.
from_i32(n: i32) -> Option<JoystickId>2687 pub fn from_i32(n: i32) -> Option<JoystickId> {
2688 if n >= 0 && n <= ffi::JOYSTICK_LAST {
2689 Some(unsafe { mem::transmute(n) })
2690 } else {
2691 None
2692 }
2693 }
2694 }
2695
2696 /// Button identifier tokens.
2697 #[repr(i32)]
2698 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2699 pub enum GamepadButton {
2700 ButtonA = ffi::GAMEPAD_BUTTON_A,
2701 ButtonB = ffi::GAMEPAD_BUTTON_B,
2702 ButtonX = ffi::GAMEPAD_BUTTON_X,
2703 ButtonY = ffi::GAMEPAD_BUTTON_Y,
2704 ButtonLeftBumper = ffi::GAMEPAD_BUTTON_LEFT_BUMPER,
2705 ButtonRightBumper = ffi::GAMEPAD_BUTTON_RIGHT_BUMPER,
2706 ButtonBack = ffi::GAMEPAD_BUTTON_BACK,
2707 ButtonStart = ffi::GAMEPAD_BUTTON_START,
2708 ButtonGuide = ffi::GAMEPAD_BUTTON_GUIDE,
2709 ButtonLeftThumb = ffi::GAMEPAD_BUTTON_LEFT_THUMB,
2710 ButtonRightThumb = ffi::GAMEPAD_BUTTON_RIGHT_THUMB,
2711 ButtonDpadUp = ffi::GAMEPAD_BUTTON_DPAD_UP,
2712 ButtonDpadRight = ffi::GAMEPAD_BUTTON_DPAD_RIGHT,
2713 ButtonDpadDown = ffi::GAMEPAD_BUTTON_DPAD_DOWN,
2714 ButtonDpadLeft = ffi::GAMEPAD_BUTTON_DPAD_LEFT,
2715 }
2716
2717 impl GamepadButton {
2718 /// Converts from `i32`.
from_i32(n: i32) -> Option<GamepadButton>2719 pub fn from_i32(n: i32) -> Option<GamepadButton> {
2720 if n >= 0 && n <= ffi::GAMEPAD_BUTTON_LAST {
2721 Some(unsafe { mem::transmute(n) })
2722 } else {
2723 None
2724 }
2725 }
2726 }
2727
2728 /// Axis identifier tokens.
2729 #[repr(i32)]
2730 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2731 pub enum GamepadAxis {
2732 AxisLeftX = ffi::GAMEPAD_AXIS_LEFT_X,
2733 AxisLeftY = ffi::GAMEPAD_AXIS_LEFT_Y,
2734 AxisRightX = ffi::GAMEPAD_AXIS_RIGHT_X,
2735 AxisRightY = ffi::GAMEPAD_AXIS_RIGHT_Y,
2736 AxisLeftTrigger = ffi::GAMEPAD_AXIS_LEFT_TRIGGER,
2737 AxisRightTrigger = ffi::GAMEPAD_AXIS_RIGHT_TRIGGER,
2738 }
2739
2740 impl GamepadAxis {
2741 /// Converts from `i32`.
from_i32(n: i32) -> Option<GamepadAxis>2742 pub fn from_i32(n: i32) -> Option<GamepadAxis> {
2743 if n >= 0 && n <= ffi::GAMEPAD_AXIS_LAST {
2744 Some(unsafe { mem::transmute(n) })
2745 } else {
2746 None
2747 }
2748 }
2749 }
2750
2751 bitflags! {
2752 #[doc = "Joystick hats."]
2753 pub struct JoystickHats: ::libc::c_int {
2754 const Centered = ::ffi::HAT_CENTERED;
2755 const Up = ::ffi::HAT_UP;
2756 const Right = ::ffi::HAT_RIGHT;
2757 const Down = ::ffi::HAT_DOWN;
2758 const Left = ::ffi::HAT_LEFT;
2759 }
2760 }
2761
2762 /// A joystick handle.
2763 #[derive(Clone)]
2764 pub struct Joystick {
2765 pub id: JoystickId,
2766 pub glfw: Glfw,
2767 }
2768
2769 /// State of a gamepad.
2770 pub struct GamepadState {
2771 buttons: [Action; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize],
2772 axes: [f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize],
2773 }
2774
2775 /// Joystick events.
2776 #[repr(i32)]
2777 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
2778 pub enum JoystickEvent {
2779 Connected = ffi::CONNECTED,
2780 Disconnected = ffi::DISCONNECTED,
2781 }
2782
2783 /// An joystick callback. This can be supplied with some user data to be passed
2784 /// to the callback function when it is triggered.
2785 pub type JoystickCallback<UserData> = Callback<fn(JoystickId, JoystickEvent, &UserData), UserData>;
2786
2787 impl Joystick {
2788 /// Wrapper for `glfwJoystickPresent`.
is_present(&self) -> bool2789 pub fn is_present(&self) -> bool {
2790 unsafe { ffi::glfwJoystickPresent(self.id as c_int) == ffi::TRUE }
2791 }
2792
2793 /// Wrapper for `glfwGetJoystickAxes`.
get_axes(&self) -> Vec<f32>2794 pub fn get_axes(&self) -> Vec<f32> {
2795 unsafe {
2796 let mut count = 0;
2797 let ptr = ffi::glfwGetJoystickAxes(self.id as c_int, &mut count);
2798 slice::from_raw_parts(ptr, count as usize).iter().map(|&a| a as f32).collect()
2799 }
2800 }
2801
2802 /// Wrapper for `glfwGetJoystickButtons`.
get_buttons(&self) -> Vec<c_int>2803 pub fn get_buttons(&self) -> Vec<c_int> {
2804 unsafe {
2805 let mut count = 0;
2806 let ptr = ffi::glfwGetJoystickButtons(self.id as c_int, &mut count);
2807 slice::from_raw_parts(ptr, count as usize).iter().map(|&b| b as c_int).collect()
2808 }
2809 }
2810
2811 /// Wrapper for `glfwGetJoystickHats`.
get_hats(&self) -> Vec<JoystickHats>2812 pub fn get_hats(&self) -> Vec<JoystickHats> {
2813 unsafe {
2814 let mut count = 0;
2815 let ptr = ffi::glfwGetJoystickHats(self.id as c_int, &mut count);
2816 slice::from_raw_parts(ptr, count as usize).iter().map(|&b| mem::transmute(b as c_int)).collect()
2817 }
2818 }
2819
2820 /// Wrapper for `glfwGetJoystickName`.
get_name(&self) -> Option<String>2821 pub fn get_name(&self) -> Option<String> {
2822 unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickName(self.id as c_int)) }
2823 }
2824
2825 /// Wrapper for `glfwGetJoystickGUID`.
get_guid(&self) -> Option<String>2826 pub fn get_guid(&self) -> Option<String> {
2827 unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickGUID(self.id as c_int)) }
2828 }
2829
2830 /// Wrapper for `glfwJoystickIsGamepad`.
is_gamepad(&self) -> bool2831 pub fn is_gamepad(&self) -> bool {
2832 unsafe { ffi::glfwJoystickIsGamepad(self.id as c_int) == ffi::TRUE }
2833 }
2834
2835 /// Wrapper for `glfwGetGamepadName`.
get_gamepad_name(&self) -> Option<String>2836 pub fn get_gamepad_name(&self) -> Option<String> {
2837 unsafe { string_from_nullable_c_str(ffi::glfwGetGamepadName(self.id as c_int)) }
2838 }
2839
2840 /// Wrapper for `glfwGetGamepadState`.
get_gamepad_state(&self) -> Option<GamepadState>2841 pub fn get_gamepad_state(&self) -> Option<GamepadState> {
2842 unsafe {
2843 let mut state = ffi::GLFWgamepadstate {
2844 buttons: [0; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize],
2845 axes: [0_f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize],
2846 };
2847 if ffi::glfwGetGamepadState(self.id as c_int, &mut state) == ffi::TRUE {
2848 Some(state.into())
2849 } else {
2850 None
2851 }
2852 }
2853 }
2854 }
2855
2856 impl From<ffi::GLFWgamepadstate> for GamepadState {
from(state: ffi::GLFWgamepadstate) -> Self2857 fn from(state: ffi::GLFWgamepadstate) -> Self {
2858 let mut buttons = [Action::Release; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize];
2859 let mut axes = [0_f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize];
2860 unsafe {
2861 state.buttons.iter().map(|&b| mem::transmute(b as c_int))
2862 .zip(buttons.iter_mut()).for_each(|(a, b)| *b = a);
2863 }
2864 state.axes.iter().map(|&f| f as f32)
2865 .zip(axes.iter_mut()).for_each(|(a, b)| *b = a);
2866 Self {
2867 buttons,
2868 axes,
2869 }
2870 }
2871 }
2872
2873 impl GamepadState {
get_button_state(&self, button: GamepadButton) -> Action2874 pub fn get_button_state(&self, button: GamepadButton) -> Action {
2875 self.buttons[button as usize]
2876 }
2877
get_axis(&self, axis: GamepadAxis) -> f322878 pub fn get_axis(&self, axis: GamepadAxis) -> f32 {
2879 self.axes[axis as usize]
2880 }
2881 }
2882