#![crate_type = "lib"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![crate_name = "glfw"]
#![allow(non_upper_case_globals)]
extern crate semver;
extern crate libc;
#[cfg(feature = "vulkan")]
extern crate vk_sys;
#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;
#[cfg(feature = "image")]
extern crate image;
extern crate raw_window_handle;
#[cfg(all(target_os="macos"))]
#[macro_use]
extern crate objc;
use libc::{c_char, c_double, c_float, c_int};
use libc::{c_ushort, c_void, c_uchar};
#[cfg(feature = "vulkan")]
use libc::c_uint;
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use std::ffi::{CStr, CString};
use std::mem;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::fmt;
use std::error;
use std::marker::Send;
use std::ptr;
use std::slice;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use semver::Version;
#[cfg(feature = "vulkan")]
use vk_sys::{
self as vk,
Instance as VkInstance,
PhysicalDevice as VkPhysicalDevice
};
pub use self::MouseButton::Button1 as MouseButtonLeft;
pub use self::MouseButton::Button2 as MouseButtonRight;
pub use self::MouseButton::Button3 as MouseButtonMiddle;
pub mod ffi;
mod callbacks;
pub type WindowId = usize;
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum Action {
Release = ffi::RELEASE,
Press = ffi::PRESS,
Repeat = ffi::REPEAT,
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum Key {
Space = ffi::KEY_SPACE,
Apostrophe = ffi::KEY_APOSTROPHE,
Comma = ffi::KEY_COMMA,
Minus = ffi::KEY_MINUS,
Period = ffi::KEY_PERIOD,
Slash = ffi::KEY_SLASH,
Num0 = ffi::KEY_0,
Num1 = ffi::KEY_1,
Num2 = ffi::KEY_2,
Num3 = ffi::KEY_3,
Num4 = ffi::KEY_4,
Num5 = ffi::KEY_5,
Num6 = ffi::KEY_6,
Num7 = ffi::KEY_7,
Num8 = ffi::KEY_8,
Num9 = ffi::KEY_9,
Semicolon = ffi::KEY_SEMICOLON,
Equal = ffi::KEY_EQUAL,
A = ffi::KEY_A,
B = ffi::KEY_B,
C = ffi::KEY_C,
D = ffi::KEY_D,
E = ffi::KEY_E,
F = ffi::KEY_F,
G = ffi::KEY_G,
H = ffi::KEY_H,
I = ffi::KEY_I,
J = ffi::KEY_J,
K = ffi::KEY_K,
L = ffi::KEY_L,
M = ffi::KEY_M,
N = ffi::KEY_N,
O = ffi::KEY_O,
P = ffi::KEY_P,
Q = ffi::KEY_Q,
R = ffi::KEY_R,
S = ffi::KEY_S,
T = ffi::KEY_T,
U = ffi::KEY_U,
V = ffi::KEY_V,
W = ffi::KEY_W,
X = ffi::KEY_X,
Y = ffi::KEY_Y,
Z = ffi::KEY_Z,
LeftBracket = ffi::KEY_LEFT_BRACKET,
Backslash = ffi::KEY_BACKSLASH,
RightBracket = ffi::KEY_RIGHT_BRACKET,
GraveAccent = ffi::KEY_GRAVE_ACCENT,
World1 = ffi::KEY_WORLD_1,
World2 = ffi::KEY_WORLD_2,
Escape = ffi::KEY_ESCAPE,
Enter = ffi::KEY_ENTER,
Tab = ffi::KEY_TAB,
Backspace = ffi::KEY_BACKSPACE,
Insert = ffi::KEY_INSERT,
Delete = ffi::KEY_DELETE,
Right = ffi::KEY_RIGHT,
Left = ffi::KEY_LEFT,
Down = ffi::KEY_DOWN,
Up = ffi::KEY_UP,
PageUp = ffi::KEY_PAGE_UP,
PageDown = ffi::KEY_PAGE_DOWN,
Home = ffi::KEY_HOME,
End = ffi::KEY_END,
CapsLock = ffi::KEY_CAPS_LOCK,
ScrollLock = ffi::KEY_SCROLL_LOCK,
NumLock = ffi::KEY_NUM_LOCK,
PrintScreen = ffi::KEY_PRINT_SCREEN,
Pause = ffi::KEY_PAUSE,
F1 = ffi::KEY_F1,
F2 = ffi::KEY_F2,
F3 = ffi::KEY_F3,
F4 = ffi::KEY_F4,
F5 = ffi::KEY_F5,
F6 = ffi::KEY_F6,
F7 = ffi::KEY_F7,
F8 = ffi::KEY_F8,
F9 = ffi::KEY_F9,
F10 = ffi::KEY_F10,
F11 = ffi::KEY_F11,
F12 = ffi::KEY_F12,
F13 = ffi::KEY_F13,
F14 = ffi::KEY_F14,
F15 = ffi::KEY_F15,
F16 = ffi::KEY_F16,
F17 = ffi::KEY_F17,
F18 = ffi::KEY_F18,
F19 = ffi::KEY_F19,
F20 = ffi::KEY_F20,
F21 = ffi::KEY_F21,
F22 = ffi::KEY_F22,
F23 = ffi::KEY_F23,
F24 = ffi::KEY_F24,
F25 = ffi::KEY_F25,
Kp0 = ffi::KEY_KP_0,
Kp1 = ffi::KEY_KP_1,
Kp2 = ffi::KEY_KP_2,
Kp3 = ffi::KEY_KP_3,
Kp4 = ffi::KEY_KP_4,
Kp5 = ffi::KEY_KP_5,
Kp6 = ffi::KEY_KP_6,
Kp7 = ffi::KEY_KP_7,
Kp8 = ffi::KEY_KP_8,
Kp9 = ffi::KEY_KP_9,
KpDecimal = ffi::KEY_KP_DECIMAL,
KpDivide = ffi::KEY_KP_DIVIDE,
KpMultiply = ffi::KEY_KP_MULTIPLY,
KpSubtract = ffi::KEY_KP_SUBTRACT,
KpAdd = ffi::KEY_KP_ADD,
KpEnter = ffi::KEY_KP_ENTER,
KpEqual = ffi::KEY_KP_EQUAL,
LeftShift = ffi::KEY_LEFT_SHIFT,
LeftControl = ffi::KEY_LEFT_CONTROL,
LeftAlt = ffi::KEY_LEFT_ALT,
LeftSuper = ffi::KEY_LEFT_SUPER,
RightShift = ffi::KEY_RIGHT_SHIFT,
RightControl = ffi::KEY_RIGHT_CONTROL,
RightAlt = ffi::KEY_RIGHT_ALT,
RightSuper = ffi::KEY_RIGHT_SUPER,
Menu = ffi::KEY_MENU,
Unknown = ffi::KEY_UNKNOWN
}
pub fn get_key_name(key: Option<Key>, scancode: Option<Scancode>) -> Option<String> {
unsafe {
string_from_nullable_c_str(ffi::glfwGetKeyName(match key {
Some(k) => k as c_int,
None => ffi::KEY_UNKNOWN
}, scancode.unwrap_or(ffi::KEY_UNKNOWN)))
}
}
#[deprecated(since = "0.16.0", note = "'key_name' can cause a segfault, use 'get_key_name' instead")]
pub fn key_name(key: Option<Key>, scancode: Option<Scancode>) -> String {
unsafe {
string_from_c_str(ffi::glfwGetKeyName(match key {
Some(k) => k as c_int,
None => ffi::KEY_UNKNOWN
}, scancode.unwrap_or(ffi::KEY_UNKNOWN)))
}
}
pub fn get_key_scancode(key: Option<Key>) -> Option<Scancode> {
unsafe {
match ffi::glfwGetKeyScancode(match key {
Some(key) => key as c_int,
None => ffi::KEY_UNKNOWN,
}) {
ffi::KEY_UNKNOWN => None,
scancode => Some(scancode as Scancode),
}
}
}
impl Key {
#[deprecated(since = "0.16.0", note = "Key method 'name' can cause a segfault, use 'get_name' instead")]
pub fn name(&self) -> String {
#[allow(deprecated)]
key_name(Some(*self), None)
}
pub fn get_name(&self) -> Option<String> {
get_key_name(Some(*self), None)
}
pub fn get_scancode(&self) -> Option<Scancode> {
get_key_scancode(Some(*self))
}
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum MouseButton {
Button1 = ffi::MOUSE_BUTTON_1,
Button2 = ffi::MOUSE_BUTTON_2,
Button3 = ffi::MOUSE_BUTTON_3,
Button4 = ffi::MOUSE_BUTTON_4,
Button5 = ffi::MOUSE_BUTTON_5,
Button6 = ffi::MOUSE_BUTTON_6,
Button7 = ffi::MOUSE_BUTTON_7,
Button8 = ffi::MOUSE_BUTTON_8,
}
impl MouseButton {
pub fn from_i32(n: i32) -> Option<MouseButton> {
if n >= 0 && n <= ffi::MOUSE_BUTTON_LAST {
Some(unsafe { mem::transmute(n) })
} else {
None
}
}
}
pub struct DebugAliases<T>(pub T);
impl fmt::Debug for DebugAliases<MouseButton> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let DebugAliases(button) = *self;
match button {
MouseButtonLeft => write!(f, "MouseButtonLeft"),
MouseButtonRight => write!(f, "MouseButtonRight"),
MouseButtonMiddle => write!(f, "MouseButtonMiddle"),
button => button.fmt(f),
}
}
}
#[derive(Copy, Clone)]
pub struct Callback<Fn, UserData> {
pub f: Fn,
pub data: UserData,
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum Error {
NoError = ffi::NO_ERROR,
NotInitialized = ffi::NOT_INITIALIZED,
NoCurrentContext = ffi::NO_CURRENT_CONTEXT,
InvalidEnum = ffi::INVALID_ENUM,
InvalidValue = ffi::INVALID_VALUE,
OutOfMemory = ffi::OUT_OF_MEMORY,
ApiUnavailable = ffi::API_UNAVAILABLE,
VersionUnavailable = ffi::VERSION_UNAVAILABLE,
PlatformError = ffi::PLATFORM_ERROR,
FormatUnavailable = ffi::FORMAT_UNAVAILABLE,
NoWindowContext = ffi::NO_WINDOW_CONTEXT,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
f.write_str(self.description())
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::NoError => "NoError",
Error::NotInitialized => "NotInitialized",
Error::NoCurrentContext => "NoCurrentContext",
Error::InvalidEnum => "InvalidEnum",
Error::InvalidValue => "InvalidValue",
Error::OutOfMemory => "OutOfMemory",
Error::ApiUnavailable => "ApiUnavailable",
Error::VersionUnavailable => "VersionUnavailable",
Error::PlatformError => "PlatformError",
Error::FormatUnavailable => "FormatUnavailable",
Error::NoWindowContext => "NoWindowContext",
}
}
}
pub type ErrorCallback<UserData> = Callback<fn(Error, String, &UserData), UserData>;
pub fn fail_on_errors(_: Error, description: String, _: &()) {
panic!("GLFW Error: {}", description);
}
pub static FAIL_ON_ERRORS: Option<ErrorCallback<()>> =
Some(Callback { f: fail_on_errors as fn(Error, String, &()), data: () });
pub fn log_errors(_: Error, description: String, _: &()) {
error!("GLFW Error: {}", description);
}
pub static LOG_ERRORS: Option<ErrorCallback<()>> =
Some(Callback { f: log_errors as fn(Error, String, &()), data: () });
pub struct PixelImage {
pub width: u32,
pub height: u32,
pub pixels: Vec<u32>
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum CursorMode {
Normal = ffi::CURSOR_NORMAL,
Hidden = ffi::CURSOR_HIDDEN,
Disabled = ffi::CURSOR_DISABLED,
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum StandardCursor {
Arrow = ffi::ARROW_CURSOR,
IBeam = ffi::IBEAM_CURSOR,
Crosshair = ffi::CROSSHAIR_CURSOR,
Hand = ffi::HAND_CURSOR,
HResize = ffi::HRESIZE_CURSOR,
VResize = ffi::VRESIZE_CURSOR
}
pub struct Cursor {
ptr: *mut ffi::GLFWcursor
}
impl Drop for Cursor {
fn drop(&mut self) {
unsafe { ffi::glfwDestroyCursor(self.ptr) }
}
}
impl Cursor {
pub fn standard(cursor: StandardCursor) -> Cursor {
Cursor {
ptr: unsafe { ffi::glfwCreateStandardCursor(cursor as c_int) }
}
}
#[cfg(feature = "image")]
pub fn create(image: image::RgbaImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
let (width, height) = image.dimensions();
let image_data = image.into_vec();
let glfw_image = ffi::GLFWimage {
width: width as c_int,
height: height as c_int,
pixels: image_data.as_ptr() as *const c_uchar
};
Cursor {
ptr: unsafe { ffi::glfwCreateCursor(&glfw_image as *const ffi::GLFWimage, x_hotspot as c_int, y_hotspot as c_int) }
}
}
pub fn create_from_pixels(image: PixelImage, x_hotspot: u32, y_hotspot: u32) -> Cursor {
let glfw_image = ffi::GLFWimage {
width: image.width as c_int,
height: image.height as c_int,
pixels: image.pixels.as_ptr() as *const c_uchar
};
Cursor {
ptr: unsafe { ffi::glfwCreateCursor(&glfw_image as *const ffi::GLFWimage, x_hotspot as c_int, y_hotspot as c_int) }
}
}
}
#[derive(Copy, Clone)]
pub struct VidMode {
pub width: u32,
pub height: u32,
pub red_bits: u32,
pub green_bits: u32,
pub blue_bits: u32,
pub refresh_rate: u32,
}
pub struct GammaRamp {
pub red: Vec<c_ushort>,
pub green: Vec<c_ushort>,
pub blue: Vec<c_ushort>,
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum ContextReleaseBehavior {
Any = ffi::ANY_RELEASE_BEHAVIOR,
Flush = ffi::RELEASE_BEHAVIOR_FLUSH,
None = ffi::RELEASE_BEHAVIOR_NONE
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum ContextCreationApi {
Native = ffi::NATIVE_CONTEXT_API,
Egl = ffi::EGL_CONTEXT_API,
OsMesa = ffi::OSMESA_CONTEXT_API,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum SwapInterval {
None,
Adaptive,
Sync(u32)
}
pub type GLProc = ffi::GLFWglproc;
#[cfg(feature = "vulkan")]
pub type VkProc = ffi::GLFWvkproc;
static REF_COUNT_FOR_GLFW: AtomicUsize = AtomicUsize::new(0);
pub struct Glfw;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum InitError {
AlreadyInitialized,
Internal,
}
impl fmt::Display for InitError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
f.write_str(self.description())
}
}
impl error::Error for InitError {
fn description(&self) -> &str {
match *self {
InitError::AlreadyInitialized => "Already Initialized",
InitError::Internal => "Internal Initialization Error",
}
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum InitHint {
JoystickHatButtons(bool),
CocoaChdirResources(bool),
CocoaMenubar(bool),
}
pub fn init_hint(hint: InitHint) {
match hint {
InitHint::JoystickHatButtons(joystick_hat_buttons) => unsafe { ffi::glfwInitHint(ffi::JOYSTICK_HAT_BUTTONS, joystick_hat_buttons as c_int) },
InitHint::CocoaChdirResources(chdir) => unsafe { ffi::glfwInitHint(ffi::COCOA_CHDIR_RESOURCES, chdir as c_int) },
InitHint::CocoaMenubar(menubar) => unsafe { ffi::glfwInitHint(ffi::COCOA_MENUBAR, menubar as c_int) },
}
}
pub fn init<UserData: 'static>(
mut callback: Option<ErrorCallback<UserData>>,
) -> Result<Glfw, InitError> {
match callback.take() {
Some(f) => callbacks::error::set(f),
None => callbacks::error::unset(),
}
if unsafe { ffi::glfwInit() } == ffi::TRUE {
REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
Ok(Glfw)
} else {
Err(InitError::Internal)
}
}
impl Glfw {
pub fn set_error_callback<UserData: 'static>(&mut self, callback: Option<ErrorCallback<UserData>>) {
match callback {
Some(f) => callbacks::error::set(f),
None => callbacks::error::unset(),
}
}
pub fn set_monitor_callback<UserData: 'static>(&mut self, callback: Option<MonitorCallback<UserData>>) {
match callback {
Some(f) => callbacks::monitor::set(f),
None => callbacks::monitor::unset(),
}
}
pub fn set_joystick_callback<UserData: 'static>(&mut self, callback: Option<JoystickCallback<UserData>>) {
match callback {
Some(f) => callbacks::joystick::set(f),
None => callbacks::joystick::unset(),
}
}
pub fn with_primary_monitor<T, F>(&mut self, f: F) -> T where F: Fn(&mut Self, Option<&Monitor>) -> T {
match unsafe { ffi::glfwGetPrimaryMonitor() } {
ptr if ptr.is_null() => f(self, None),
ptr => f(self, Some(&Monitor {
ptr: ptr
})),
}
}
pub fn with_primary_monitor_mut<T, F>(&mut self, mut f: F) -> T where F: FnMut(&mut Self, Option<&Monitor>) -> T {
match unsafe { ffi::glfwGetPrimaryMonitor() } {
ptr if ptr.is_null() => f(self, None),
ptr => f(self, Some(&Monitor {
ptr: ptr
})),
}
}
pub fn with_connected_monitors<T, F>(&mut self, f: F) -> T where F: Fn(&mut Self, &[Monitor]) -> T {
unsafe {
let mut count = 0;
let ptr = ffi::glfwGetMonitors(&mut count);
f(self,
&slice::from_raw_parts(ptr as *const _, count as usize).iter().map(|&ptr| {
Monitor {
ptr: ptr
}
}).collect::<Vec<Monitor>>())
}
}
pub fn with_connected_monitors_mut<T, F>(&mut self, mut f: F) -> T where F: FnMut(&mut Self, &[Monitor]) -> T {
unsafe {
let mut count = 0;
let ptr = ffi::glfwGetMonitors(&mut count);
f(self,
&slice::from_raw_parts(ptr as *const _, count as usize).iter().map(|&ptr| {
Monitor {
ptr: ptr
}
}).collect::<Vec<Monitor>>())
}
}
#[cfg(feature = "vulkan")]
pub fn vulkan_supported(&self) -> bool {
unsafe { ffi::glfwVulkanSupported() == ffi::TRUE }
}
pub fn window_hint(&mut self, hint: WindowHint) {
#[inline(always)]
unsafe fn dont_care_hint(hint: c_int, value: Option<u32>) {
ffi::glfwWindowHint(hint, match value {
Some(v) => v as c_int,
None => ffi::DONT_CARE
})
}
#[inline(always)]
unsafe fn string_hint(hint: c_int, value: Option<String>) {
let value = if let Some(value) = &value {
value.as_str()
} else {
""
};
with_c_str(value, |value| {
ffi::glfwWindowHintString(hint, value)
})
}
match hint {
WindowHint::RedBits(bits) => unsafe { dont_care_hint(ffi::RED_BITS, bits) },
WindowHint::GreenBits(bits) => unsafe { dont_care_hint(ffi::GREEN_BITS, bits) },
WindowHint::BlueBits(bits) => unsafe { dont_care_hint(ffi::BLUE_BITS, bits) },
WindowHint::AlphaBits(bits) => unsafe { dont_care_hint(ffi::ALPHA_BITS, bits) },
WindowHint::DepthBits(bits) => unsafe { dont_care_hint(ffi::DEPTH_BITS, bits) },
WindowHint::StencilBits(bits) => unsafe { dont_care_hint(ffi::STENCIL_BITS, bits) },
WindowHint::AccumRedBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_RED_BITS, bits) },
WindowHint::AccumGreenBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_GREEN_BITS, bits) },
WindowHint::AccumBlueBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_BLUE_BITS, bits) },
WindowHint::AccumAlphaBits(bits) => unsafe { dont_care_hint(ffi::ACCUM_ALPHA_BITS, bits) },
WindowHint::AuxBuffers(num_buffers) => unsafe { dont_care_hint(ffi::AUX_BUFFERS, num_buffers) },
WindowHint::Samples(num_samples) => unsafe { dont_care_hint(ffi::SAMPLES, num_samples) },
WindowHint::RefreshRate(rate) => unsafe { dont_care_hint(ffi::REFRESH_RATE, rate) },
WindowHint::Stereo(is_stereo) => unsafe { ffi::glfwWindowHint(ffi::STEREO, is_stereo as c_int) },
WindowHint::SRgbCapable(is_capable) => unsafe { ffi::glfwWindowHint(ffi::SRGB_CAPABLE, is_capable as c_int) },
WindowHint::ClientApi(api) => unsafe { ffi::glfwWindowHint(ffi::CLIENT_API, api as c_int) },
WindowHint::ContextVersionMajor(major) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MAJOR, major as c_int) },
WindowHint::ContextVersionMinor(minor) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MINOR, minor as c_int) },
WindowHint::ContextVersion(major, minor) => unsafe {
ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MAJOR, major as c_int);
ffi::glfwWindowHint(ffi::CONTEXT_VERSION_MINOR, minor as c_int)
},
WindowHint::ContextRobustness(robustness) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_ROBUSTNESS, robustness as c_int) },
WindowHint::OpenGlForwardCompat(is_compat) => unsafe { ffi::glfwWindowHint(ffi::OPENGL_FORWARD_COMPAT, is_compat as c_int) },
WindowHint::OpenGlDebugContext(is_debug) => unsafe { ffi::glfwWindowHint(ffi::OPENGL_DEBUG_CONTEXT, is_debug as c_int) },
WindowHint::OpenGlProfile(profile) => unsafe { ffi::glfwWindowHint(ffi::OPENGL_PROFILE, profile as c_int) },
WindowHint::Resizable(is_resizable) => unsafe { ffi::glfwWindowHint(ffi::RESIZABLE, is_resizable as c_int) },
WindowHint::Visible(is_visible) => unsafe { ffi::glfwWindowHint(ffi::VISIBLE, is_visible as c_int) },
WindowHint::Decorated(is_decorated) => unsafe { ffi::glfwWindowHint(ffi::DECORATED, is_decorated as c_int) },
WindowHint::AutoIconify(auto_iconify) => unsafe { ffi::glfwWindowHint(ffi::AUTO_ICONIFY, auto_iconify as c_int) },
WindowHint::Floating(is_floating) => unsafe { ffi::glfwWindowHint(ffi::FLOATING, is_floating as c_int) },
WindowHint::Focused(is_focused) => unsafe { ffi::glfwWindowHint(ffi::FOCUSED, is_focused as c_int) },
WindowHint::ContextNoError(is_no_error) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_NO_ERROR, is_no_error as c_int) },
WindowHint::ContextCreationApi(api) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_CREATION_API, api as c_int) },
WindowHint::ContextReleaseBehavior(behavior) => unsafe { ffi::glfwWindowHint(ffi::CONTEXT_RELEASE_BEHAVIOR, behavior as c_int) },
WindowHint::DoubleBuffer(is_dbuffered) => unsafe { ffi::glfwWindowHint(ffi::DOUBLEBUFFER, is_dbuffered as c_int) },
WindowHint::CenterCursor(center_cursor) => unsafe { ffi::glfwWindowHint(ffi::CENTER_CURSOR, center_cursor as c_int) },
WindowHint::TransparentFramebuffer(is_transparent) => unsafe { ffi::glfwWindowHint(ffi::TRANSPARENT_FRAMEBUFFER, is_transparent as c_int) },
WindowHint::FocusOnShow(focus) => unsafe { ffi::glfwWindowHint(ffi::FOCUS_ON_SHOW, focus as c_int) },
WindowHint::ScaleToMonitor(scale) => unsafe { ffi::glfwWindowHint(ffi::SCALE_TO_MONITOR, scale as c_int) },
WindowHint::CocoaRetinaFramebuffer(retina_fb) => unsafe { ffi::glfwWindowHint(ffi::COCOA_RETINA_FRAMEBUFFER, retina_fb as c_int) },
WindowHint::CocoaFrameName(name) => unsafe { string_hint(ffi::COCOA_FRAME_NAME, name) }
WindowHint::CocoaGraphicsSwitching(graphics_switching) => unsafe { ffi::glfwWindowHint(ffi::COCOA_GRAPHICS_SWITCHING, graphics_switching as c_int) },
WindowHint::X11ClassName(class_name) => unsafe { string_hint(ffi::X11_CLASS_NAME, class_name) },
WindowHint::X11InstanceName(instance_name) => unsafe { string_hint(ffi::X11_INSTANCE_NAME, instance_name) },
}
}
pub fn default_window_hints(&mut self) {
unsafe { ffi::glfwDefaultWindowHints(); }
}
pub fn create_window(&self, width: u32, height: u32, title: &str, mode: WindowMode) -> Option<(Window, Receiver<(f64, WindowEvent)>)> {
self.create_window_intern(width, height, title, mode, None)
}
fn create_window_intern(&self, width: u32, height: u32, title: &str, mode: WindowMode, share: Option<&Window>) -> Option<(Window, Receiver<(f64, WindowEvent)>)> {
let ptr = unsafe {
with_c_str(title, |title| {
ffi::glfwCreateWindow(
width as c_int,
height as c_int,
title,
mode.to_ptr(),
match share { Some(w) => w.ptr, None => ptr::null_mut() }
)
})
};
if ptr.is_null() {
None
} else {
let (drop_sender, drop_receiver) = channel();
let (sender, receiver) = channel();
unsafe { ffi::glfwSetWindowUserPointer(ptr, mem::transmute(Box::new(sender))); }
Some((
Window {
ptr: ptr,
glfw: self.clone(),
is_shared: share.is_some(),
drop_sender: Some(drop_sender),
drop_receiver: drop_receiver,
current_cursor: None
},
receiver,
))
}
}
pub fn make_context_current(&mut self, context: Option<&Window>) {
match context {
Some(window) => unsafe { ffi::glfwMakeContextCurrent(window.ptr) },
None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
}
}
#[cfg(target_os="linux")]
pub fn get_x11_display(&self) -> *mut c_void {
unsafe { ffi::glfwGetX11Display() }
}
pub fn poll_events(&mut self) {
unsafe { ffi::glfwPollEvents(); }
}
pub fn poll_events_unbuffered<F>(&mut self, mut f: F)
where
F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>
{
let _unset_handler_guard = unsafe {
crate::callbacks::unbuffered::set_handler(&mut f)
};
self.poll_events();
}
pub fn wait_events(&mut self) {
unsafe { ffi::glfwWaitEvents(); }
}
pub fn wait_events_unbuffered<F>(&mut self, mut f: F)
where
F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>
{
let _unset_handler_guard = unsafe {
crate::callbacks::unbuffered::set_handler(&mut f)
};
self.wait_events();
}
pub fn wait_events_timeout(&mut self, timeout: f64) {
unsafe { ffi::glfwWaitEventsTimeout(timeout); }
}
pub fn wait_events_timeout_unbuffered<F>(&mut self, timeout: f64, mut f: F)
where
F: FnMut(WindowId, (f64, WindowEvent)) -> Option<(f64, WindowEvent)>
{
let _unset_handler_guard = unsafe {
crate::callbacks::unbuffered::set_handler(&mut f)
};
self.wait_events_timeout(timeout);
}
pub fn post_empty_event(&mut self) {
unsafe { ffi::glfwPostEmptyEvent(); }
}
pub fn get_time(&self) -> f64 {
unsafe { ffi::glfwGetTime() as f64 }
}
pub fn set_time(&mut self, time: f64) {
unsafe { ffi::glfwSetTime(time as c_double); }
}
pub fn get_timer_value() -> u64 {
unsafe { ffi::glfwGetTimerValue() as u64 }
}
pub fn get_timer_frequency() -> u64 {
unsafe { ffi::glfwGetTimerFrequency() as u64 }
}
pub fn set_swap_interval(&mut self, interval: SwapInterval) {
unsafe {
ffi::glfwSwapInterval(match interval {
SwapInterval::None => 0 as c_int,
SwapInterval::Adaptive => -1 as c_int,
SwapInterval::Sync(interval) => interval as c_int
})
}
}
pub fn extension_supported(&self, extension: &str) -> bool {
unsafe {
with_c_str(extension, |extension| {
ffi::glfwExtensionSupported(extension) == ffi::TRUE
})
}
}
#[cfg(feature = "vulkan")]
pub fn get_required_instance_extensions(&self) -> Option<Vec<String>> {
let mut len: c_uint = 0;
unsafe {
let raw_extensions: *const *const c_char = ffi::glfwGetRequiredInstanceExtensions(&mut len as *mut c_uint);
if !raw_extensions.is_null() {
return Some(slice::from_raw_parts(raw_extensions, len as usize)
.iter()
.map(|extensions| string_from_c_str(*extensions))
.collect());
}
}
None
}
pub fn get_proc_address_raw(&self, procname: &str) -> GLProc {
debug_assert!(unsafe { ffi::glfwGetCurrentContext() } != std::ptr::null_mut());
with_c_str(procname, |procname| {
unsafe { ffi::glfwGetProcAddress(procname) }
})
}
#[cfg(feature = "vulkan")]
pub fn get_instance_proc_address_raw(&self, instance: VkInstance, procname: &str) -> VkProc {
with_c_str(procname, |procname| {
unsafe { ffi::glfwGetInstanceProcAddress(instance, procname) }
})
}
#[cfg(feature = "vulkan")]
pub fn get_physical_device_presentation_support_raw(&self, instance: VkInstance, device: VkPhysicalDevice, queue_family: u32) -> bool {
vk::TRUE == unsafe { ffi::glfwGetPhysicalDevicePresentationSupport(instance, device, queue_family as c_uint) as u32 }
}
pub fn get_joystick(&self, id: JoystickId) -> Joystick {
Joystick { id: id, glfw: self.clone() }
}
pub fn supports_raw_motion(&self) -> bool {
unsafe { ffi::glfwRawMouseMotionSupported() == ffi::TRUE }
}
pub fn update_gamepad_mappings(&self, mappings: &str) -> bool {
unsafe {
let c_str = CString::new(mappings.as_bytes());
let ptr = c_str.unwrap().as_bytes_with_nul().as_ptr() as *const c_char;
ffi::glfwUpdateGamepadMappings(ptr) == ffi::TRUE
}
}
}
impl Clone for Glfw {
fn clone(&self) -> Self {
REF_COUNT_FOR_GLFW.fetch_add(1, Ordering::SeqCst);
Glfw
}
}
impl Drop for Glfw {
fn drop(&mut self) {
let old_diff = REF_COUNT_FOR_GLFW.fetch_sub(1, Ordering::SeqCst);
if old_diff == 1 {
unsafe { ffi::glfwTerminate(); }
}
}
}
pub fn get_version() -> Version {
unsafe {
let mut major = 0;
let mut minor = 0;
let mut patch = 0;
ffi::glfwGetVersion(&mut major, &mut minor, &mut patch);
Version {
major: major as u64,
minor: minor as u64,
patch: patch as u64,
pre: Vec::new(),
build: Vec::new(),
}
}
}
pub unsafe fn string_from_c_str(c_str: *const c_char) -> String {
String::from_utf8_lossy(CStr::from_ptr(c_str).to_bytes()).into_owned()
}
pub unsafe fn string_from_nullable_c_str(c_str: *const c_char) -> Option<String> {
if c_str.is_null() {
None
} else {
Some(string_from_c_str(c_str))
}
}
pub fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const c_char) -> T {
let c_str = CString::new(s.as_bytes());
f(c_str.unwrap().as_bytes_with_nul().as_ptr() as *const _)
}
pub fn get_version_string() -> String {
unsafe { string_from_c_str(ffi::glfwGetVersionString()) }
}
pub type MonitorCallback<UserData> = Callback<fn(Monitor, MonitorEvent, &UserData), UserData>;
#[allow(missing_copy_implementations)]
pub struct Monitor {
ptr: *mut ffi::GLFWmonitor
}
impl std::fmt::Debug for Monitor {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Monitor({:p})", self.ptr)
}
}
impl Monitor {
pub fn get_pos(&self) -> (i32, i32) {
unsafe {
let mut xpos = 0;
let mut ypos = 0;
ffi::glfwGetMonitorPos(self.ptr, &mut xpos, &mut ypos);
(xpos as i32, ypos as i32)
}
}
pub fn get_physical_size(&self) -> (i32, i32) {
unsafe {
let mut width = 0;
let mut height = 0;
ffi::glfwGetMonitorPhysicalSize(self.ptr, &mut width, &mut height);
(width as i32, height as i32)
}
}
pub fn get_name(&self) -> Option<String> {
unsafe { string_from_nullable_c_str(ffi::glfwGetMonitorName(self.ptr)) }
}
pub fn get_video_modes(&self) -> Vec<VidMode> {
unsafe {
let mut count = 0;
let ptr = ffi::glfwGetVideoModes(self.ptr, &mut count);
slice::from_raw_parts(ptr, count as usize).iter().map(VidMode::from_glfw_vid_mode).collect()
}
}
pub fn get_video_mode(&self) -> Option<VidMode> {
unsafe {
let ptr = ffi::glfwGetVideoMode(self.ptr);
if ptr.is_null() {
None
} else {
Some(VidMode::from_glfw_vid_mode(&*ptr))
}
}
}
pub fn set_gamma(&mut self, gamma: f32) {
unsafe { ffi::glfwSetGamma(self.ptr, gamma as c_float); }
}
pub fn get_gamma_ramp(&self) -> GammaRamp {
unsafe {
let llramp = *ffi::glfwGetGammaRamp(self.ptr);
GammaRamp {
red: slice::from_raw_parts(llramp.red as *const c_ushort, llramp.size as usize)
.iter().map(|&x| x).collect(),
green: slice::from_raw_parts(llramp.green as *const c_ushort, llramp.size as usize)
.iter().map(|&x| x).collect(),
blue: slice::from_raw_parts(llramp.blue as *const c_ushort, llramp.size as usize)
.iter().map(|&x| x).collect(),
}
}
}
pub fn set_gamma_ramp(&mut self, ramp: &mut GammaRamp) {
unsafe {
ffi::glfwSetGammaRamp(
self.ptr,
&ffi::GLFWgammaramp {
red: ramp.red.as_mut_ptr(),
green: ramp.green.as_mut_ptr(),
blue: ramp.blue.as_mut_ptr(),
size: ramp.red.len() as u32,
}
);
}
}
pub fn get_content_scale(&self) -> (f32, f32) {
unsafe {
let mut xscale = 0.0_f32;
let mut yscale = 0.0_f32;
ffi::glfwGetMonitorContentScale(self.ptr, &mut xscale, &mut yscale);
(xscale, yscale)
}
}
pub fn get_workarea(&self) -> (i32, i32, i32, i32) {
unsafe {
let mut xpos = 0;
let mut ypos = 0;
let mut width = 0;
let mut height = 0;
ffi::glfwGetMonitorWorkarea(self.ptr, &mut xpos, &mut ypos, &mut width, &mut height);
(xpos, ypos, width, height)
}
}
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum MonitorEvent {
Connected = ffi::CONNECTED,
Disconnected = ffi::DISCONNECTED,
}
impl VidMode {
fn from_glfw_vid_mode(mode: &ffi::GLFWvidmode) -> VidMode {
VidMode {
width: mode.width as u32,
height: mode.height as u32,
red_bits: mode.redBits as u32,
green_bits: mode.greenBits as u32,
blue_bits: mode.blueBits as u32,
refresh_rate: mode.refreshRate as u32,
}
}
}
impl fmt::Debug for VidMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} x {}, {} = {} + {} + {}, {} Hz",
self.width, self.height,
self.red_bits + self.green_bits + self.blue_bits,
self.red_bits, self.green_bits, self.blue_bits,
self.refresh_rate)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum WindowHint {
RedBits(Option<u32>),
GreenBits(Option<u32>),
BlueBits(Option<u32>),
AlphaBits(Option<u32>),
DepthBits(Option<u32>),
StencilBits(Option<u32>),
AccumRedBits(Option<u32>),
AccumGreenBits(Option<u32>),
AccumBlueBits(Option<u32>),
AccumAlphaBits(Option<u32>),
AuxBuffers(Option<u32>),
Stereo(bool),
Samples(Option<u32>),
SRgbCapable(bool),
RefreshRate(Option<u32>),
ClientApi(ClientApiHint),
ContextVersionMajor(u32),
ContextVersionMinor(u32),
ContextVersion(u32, u32),
ContextRobustness(ContextRobustnessHint),
OpenGlForwardCompat(bool),
OpenGlDebugContext(bool),
OpenGlProfile(OpenGlProfileHint),
Resizable(bool),
Visible(bool),
Decorated(bool),
AutoIconify(bool),
Floating(bool),
Focused(bool),
ContextNoError(bool),
ContextCreationApi(ContextCreationApi),
ContextReleaseBehavior(ContextReleaseBehavior),
DoubleBuffer(bool),
CenterCursor(bool),
TransparentFramebuffer(bool),
FocusOnShow(bool),
ScaleToMonitor(bool),
CocoaRetinaFramebuffer(bool),
CocoaFrameName(Option<String>),
CocoaGraphicsSwitching(bool),
X11ClassName(Option<String>),
X11InstanceName(Option<String>),
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum ClientApiHint {
NoApi = ffi::NO_API,
OpenGl = ffi::OPENGL_API,
OpenGlEs = ffi::OPENGL_ES_API,
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum ContextRobustnessHint {
NoRobustness = ffi::NO_ROBUSTNESS,
NoResetNotification = ffi::NO_RESET_NOTIFICATION,
LoseContextOnReset = ffi::LOSE_CONTEXT_ON_RESET,
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum OpenGlProfileHint {
Any = ffi::OPENGL_ANY_PROFILE,
Core = ffi::OPENGL_CORE_PROFILE,
Compat = ffi::OPENGL_COMPAT_PROFILE,
}
#[derive(Copy, Clone, Debug)]
pub enum WindowMode<'a> {
FullScreen(&'a Monitor),
Windowed,
}
impl<'a> WindowMode<'a> {
fn to_ptr(&self) -> *mut ffi::GLFWmonitor {
match *self {
WindowMode::FullScreen(ref monitor) => monitor.ptr,
WindowMode::Windowed => ptr::null_mut(),
}
}
}
bitflags! {
#[doc = "Key modifiers (e.g., Shift, Control, Alt, Super)"]
pub struct Modifiers: ::libc::c_int {
const Shift = ::ffi::MOD_SHIFT;
const Control = ::ffi::MOD_CONTROL;
const Alt = ::ffi::MOD_ALT;
const Super = ::ffi::MOD_SUPER;
const CapsLock = ::ffi::MOD_CAPS_LOCK;
const NumLock = ::ffi::MOD_NUM_LOCK;
}
}
pub type Scancode = c_int;
#[derive(Clone, PartialEq, PartialOrd, Debug)]
pub enum WindowEvent {
Pos(i32, i32),
Size(i32, i32),
Close,
Refresh,
Focus(bool),
Iconify(bool),
FramebufferSize(i32, i32),
MouseButton(MouseButton, Action, Modifiers),
CursorPos(f64, f64),
CursorEnter(bool),
Scroll(f64, f64),
Key(Key, Scancode, Action, Modifiers),
Char(char),
CharModifiers(char, Modifiers),
FileDrop(Vec<PathBuf>),
Maximize(bool),
ContentScale(f32, f32),
}
pub fn flush_messages<'a, Message: Send>(receiver: &'a Receiver<Message>) -> FlushedMessages<'a, Message> {
FlushedMessages(receiver)
}
pub struct FlushedMessages<'a, Message: 'a + Send>(&'a Receiver<Message>);
unsafe impl<'a, Message: 'a + Send> Send for FlushedMessages<'a, Message> {
}
impl<'a, Message: 'static + Send> Iterator for FlushedMessages<'a, Message> {
type Item = Message;
fn next(&mut self) -> Option<Message> {
let FlushedMessages(receiver) = *self;
match receiver.try_recv() {
Ok(message) => Some(message),
_ => None,
}
}
}
pub struct Window {
ptr: *mut ffi::GLFWwindow,
pub glfw: Glfw,
pub is_shared: bool,
drop_sender: Option<Sender<()>>,
drop_receiver: Receiver<()>,
current_cursor: Option<Cursor>
}
macro_rules! set_window_callback {
($window:ident, $should_poll:expr, $ll_fn:ident, $callback:ident) => ({
if $should_poll {
unsafe { ffi::$ll_fn($window.ptr, Some(callbacks::$callback)); }
} else {
unsafe { ffi::$ll_fn($window.ptr, None); }
}
})
}
impl Window {
pub fn get_proc_address(&mut self, procname: &str) -> GLProc {
if self.ptr != unsafe { ffi::glfwGetCurrentContext() } {
self.make_current();
}
self.glfw.get_proc_address_raw(procname)
}
#[cfg(feature = "vulkan")]
pub fn get_instance_proc_address(&mut self, instance: VkInstance, procname: &str) -> VkProc {
self.glfw.get_instance_proc_address_raw(instance, procname)
}
#[cfg(feature = "vulkan")]
pub fn get_physical_device_presentation_support(&self, instance: VkInstance, device: VkPhysicalDevice, queue_family: u32) -> bool {
self.glfw.get_physical_device_presentation_support_raw(instance, device, queue_family)
}
pub fn create_shared(&self, width: u32, height: u32, title: &str, mode: WindowMode) -> Option<(Window, Receiver<(f64, WindowEvent)>)> {
self.glfw.create_window_intern(width, height, title, mode, Some(self))
}
pub fn close(self) {}
pub fn render_context(&mut self) -> RenderContext {
RenderContext {
ptr: self.ptr,
drop_sender: self.drop_sender.as_ref().unwrap().clone()
}
}
pub fn should_close(&self) -> bool {
unsafe { ffi::glfwWindowShouldClose(self.ptr) == ffi::TRUE }
}
pub fn set_should_close(&mut self, value: bool) {
unsafe { ffi::glfwSetWindowShouldClose(self.ptr, value as c_int) }
}
pub fn set_title(&mut self, title: &str) {
unsafe {
with_c_str(title, |title| {
ffi::glfwSetWindowTitle(self.ptr, title);
});
}
}
pub fn get_pos(&self) -> (i32, i32) {
unsafe {
let mut xpos = 0;
let mut ypos = 0;
ffi::glfwGetWindowPos(self.ptr, &mut xpos, &mut ypos);
(xpos as i32, ypos as i32)
}
}
pub fn set_pos(&mut self, xpos: i32, ypos: i32) {
unsafe { ffi::glfwSetWindowPos(self.ptr, xpos as c_int, ypos as c_int); }
}
pub fn get_size(&self) -> (i32, i32) {
unsafe {
let mut width = 0;
let mut height = 0;
ffi::glfwGetWindowSize(self.ptr, &mut width, &mut height);
(width as i32, height as i32)
}
}
pub fn set_size(&mut self, width: i32, height: i32) {
unsafe { ffi::glfwSetWindowSize(self.ptr, width as c_int, height as c_int); }
}
pub fn get_frame_size(&self) -> (i32, i32, i32, i32) {
let (mut left, mut top, mut right, mut bottom): (i32, i32, i32, i32) = (0, 0, 0, 0);
unsafe {
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);
}
(left, top, right, bottom)
}
pub fn get_framebuffer_size(&self) -> (i32, i32) {
unsafe {
let mut width = 0;
let mut height = 0;
ffi::glfwGetFramebufferSize(self.ptr, &mut width, &mut height);
(width as i32, height as i32)
}
}
pub fn set_aspect_ratio(&mut self, numer: u32, denum: u32) {
unsafe { ffi::glfwSetWindowAspectRatio(self.ptr, numer as c_int, denum as c_int) }
}
pub fn set_size_limits(&mut self, minwidth: u32, minheight: u32, maxwidth: u32, maxheight: u32) {
unsafe { ffi::glfwSetWindowSizeLimits(self.ptr , minwidth as c_int, minheight as c_int, maxwidth as c_int, maxheight as c_int) }
}
pub fn iconify(&mut self) {
unsafe { ffi::glfwIconifyWindow(self.ptr); }
}
pub fn restore(&mut self) {
unsafe { ffi::glfwRestoreWindow(self.ptr); }
}
pub fn maximize(&mut self) {
unsafe { ffi::glfwMaximizeWindow(self.ptr) }
}
pub fn show(&mut self) {
unsafe { ffi::glfwShowWindow(self.ptr); }
}
pub fn hide(&mut self) {
unsafe { ffi::glfwHideWindow(self.ptr); }
}
pub fn with_window_mode<T, F>(&self, f: F) -> T where F: Fn(WindowMode) -> T {
let ptr = unsafe { ffi::glfwGetWindowMonitor(self.ptr) };
if ptr.is_null() {
f(WindowMode::Windowed)
} else {
f(WindowMode::FullScreen(&Monitor {
ptr: ptr
}))
}
}
pub fn with_window_mode_mut<T, F>(&self, mut f: F) -> T where F: FnMut(WindowMode) -> T {
let ptr = unsafe { ffi::glfwGetWindowMonitor(self.ptr) };
if ptr.is_null() {
f(WindowMode::Windowed)
} else {
f(WindowMode::FullScreen(&Monitor {
ptr: ptr
}))
}
}
pub fn set_monitor(&mut self, mode: WindowMode, xpos: i32, ypos: i32, width: u32, height: u32, refresh_rate: Option<u32>) {
let monitor_ptr = if let WindowMode::FullScreen(ref monitor) = mode { monitor.ptr } else { ptr::null_mut() };
unsafe {
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 {
Some(value) => value as c_int,
None => ffi::DONT_CARE
})
}
}
pub fn focus(&mut self) {
unsafe { ffi::glfwFocusWindow(self.ptr) }
}
pub fn is_focused(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FOCUSED) == ffi::TRUE }
}
pub fn is_iconified(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::ICONIFIED) == ffi::TRUE }
}
pub fn is_maximized(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::MAXIMIZED) == ffi::TRUE }
}
pub fn get_client_api(&self) -> c_int {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::CLIENT_API) }
}
pub fn get_context_version(&self) -> Version {
unsafe {
Version {
major: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_VERSION_MAJOR) as u64,
minor: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_VERSION_MINOR) as u64,
patch: ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_REVISION) as u64,
pre: Vec::new(),
build: Vec::new(),
}
}
}
pub fn get_context_robustness(&self) -> c_int {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::CONTEXT_ROBUSTNESS) }
}
pub fn is_opengl_forward_compat(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_FORWARD_COMPAT) == ffi::TRUE }
}
pub fn is_opengl_debug_context(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_DEBUG_CONTEXT) == ffi::TRUE }
}
pub fn get_opengl_profile(&self) -> c_int {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::OPENGL_PROFILE) }
}
pub fn is_resizable(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::RESIZABLE) == ffi::TRUE }
}
pub fn set_resizable(&mut self, resizable: bool) {
unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::RESIZABLE, resizable as c_int) }
}
pub fn is_visible(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::VISIBLE) == ffi::TRUE }
}
pub fn is_decorated(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::DECORATED) == ffi::TRUE }
}
pub fn set_decorated(&mut self, decorated: bool) {
unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::DECORATED, decorated as c_int) }
}
pub fn is_auto_iconify(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::AUTO_ICONIFY) == ffi::TRUE }
}
pub fn set_auto_iconify(&mut self, auto_iconify: bool) {
unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::AUTO_ICONIFY, auto_iconify as c_int) }
}
pub fn is_floating(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FLOATING) == ffi::TRUE }
}
pub fn set_floating(&mut self, floating: bool) {
unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::FLOATING, floating as c_int) }
}
pub fn is_framebuffer_transparent(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::TRANSPARENT_FRAMEBUFFER) == ffi::TRUE }
}
pub fn is_focus_on_show(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::FOCUS_ON_SHOW) == ffi::TRUE }
}
pub fn set_focus_on_show(&mut self, focus_on_show: bool) {
unsafe { ffi::glfwSetWindowAttrib(self.ptr, ffi::FOCUS_ON_SHOW, focus_on_show as c_int) }
}
pub fn is_hovered(&self) -> bool {
unsafe { ffi::glfwGetWindowAttrib(self.ptr, ffi::HOVERED) == ffi::TRUE }
}
pub fn set_pos_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowPosCallback, window_pos_callback);
}
pub fn set_all_polling(&mut self, should_poll: bool) {
self.set_pos_polling(should_poll);
self.set_size_polling(should_poll);
self.set_close_polling(should_poll);
self.set_refresh_polling(should_poll);
self.set_focus_polling(should_poll);
self.set_iconify_polling(should_poll);
self.set_framebuffer_size_polling(should_poll);
self.set_key_polling(should_poll);
self.set_char_polling(should_poll);
self.set_char_mods_polling(should_poll);
self.set_mouse_button_polling(should_poll);
self.set_cursor_pos_polling(should_poll);
self.set_cursor_enter_polling(should_poll);
self.set_scroll_polling(should_poll);
self.set_drag_and_drop_polling(should_poll);
self.set_maximize_polling(should_poll);
self.set_content_scale_polling(should_poll);
}
pub fn set_size_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowSizeCallback, window_size_callback);
}
pub fn set_close_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowCloseCallback, window_close_callback);
}
pub fn set_refresh_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowRefreshCallback, window_refresh_callback);
}
pub fn set_focus_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowFocusCallback, window_focus_callback);
}
pub fn set_iconify_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowIconifyCallback, window_iconify_callback);
}
pub fn set_framebuffer_size_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetFramebufferSizeCallback, framebuffer_size_callback);
}
pub fn set_drag_and_drop_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetDropCallback, drop_callback);
}
pub fn set_maximize_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowMaximizeCallback, window_maximize_callback);
}
pub fn set_content_scale_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetWindowContentScaleCallback, window_content_scale_callback);
}
pub fn get_cursor_mode(&self) -> CursorMode {
unsafe { mem::transmute(ffi::glfwGetInputMode(self.ptr, ffi::CURSOR)) }
}
pub fn set_cursor_mode(&mut self, mode: CursorMode) {
unsafe { ffi::glfwSetInputMode(self.ptr, ffi::CURSOR, mode as c_int); }
}
pub fn set_cursor(&mut self, cursor: Option<Cursor>) -> Option<Cursor> {
let previous = mem::replace(&mut self.current_cursor, cursor);
unsafe {
ffi::glfwSetCursor(self.ptr, match self.current_cursor {
Some(ref cursor) => cursor.ptr,
None => ptr::null_mut()
})
}
previous
}
#[cfg(feature = "image")]
pub fn set_icon(&mut self, images: Vec<image::RgbaImage>) {
let image_data : Vec<(Vec<_>, u32, u32)> = images.into_iter().map(|image| {
let (width, height) = image.dimensions();
(image.into_vec(), width, height)
}).collect();
let glfw_images: Vec<ffi::GLFWimage> = image_data.iter().map(|ref data| {
ffi::GLFWimage {
width: data.1 as c_int,
height: data.2 as c_int,
pixels: data.0.as_ptr() as *const c_uchar
}
}).collect();
unsafe {
ffi::glfwSetWindowIcon(self.ptr, glfw_images.len() as c_int, glfw_images.as_ptr() as *const ffi::GLFWimage)
}
}
pub fn set_icon_from_pixels(&mut self, images: Vec<PixelImage>) {
let glfw_images: Vec<ffi::GLFWimage> = images.iter().map(|image: &PixelImage| {
ffi::GLFWimage {
width: image.width as c_int,
height: image.height as c_int,
pixels: image.pixels.as_ptr() as *const c_uchar
}
}).collect();
unsafe {
ffi::glfwSetWindowIcon(self.ptr, glfw_images.len() as c_int, glfw_images.as_ptr() as *const ffi::GLFWimage)
}
}
pub fn has_sticky_keys(&self) -> bool {
unsafe { ffi::glfwGetInputMode(self.ptr, ffi::STICKY_KEYS) == ffi::TRUE }
}
pub fn set_sticky_keys(&mut self, value: bool) {
unsafe { ffi::glfwSetInputMode(self.ptr, ffi::STICKY_KEYS, value as c_int); }
}
pub fn has_sticky_mouse_buttons(&self) -> bool {
unsafe { ffi::glfwGetInputMode(self.ptr, ffi::STICKY_MOUSE_BUTTONS) == ffi::TRUE }
}
pub fn set_sticky_mouse_buttons(&mut self, value: bool) {
unsafe { ffi::glfwSetInputMode(self.ptr, ffi::STICKY_MOUSE_BUTTONS, value as c_int); }
}
pub fn does_store_lock_key_mods(&self) -> bool {
unsafe { ffi::glfwGetInputMode(self.ptr, ffi::LOCK_KEY_MODS) == ffi::TRUE }
}
pub fn set_store_lock_key_mods(&mut self, value: bool) {
unsafe { ffi::glfwSetInputMode(self.ptr, ffi::LOCK_KEY_MODS, value as c_int) }
}
pub fn uses_raw_mouse_motion(&self) -> bool {
unsafe { ffi::glfwGetInputMode(self.ptr, ffi::RAW_MOUSE_MOTION) == ffi::TRUE }
}
pub fn set_raw_mouse_motion(&mut self, value: bool) {
unsafe { ffi::glfwSetInputMode(self.ptr, ffi::RAW_MOUSE_MOTION, value as c_int) }
}
pub fn get_key(&self, key: Key) -> Action {
unsafe { mem::transmute(ffi::glfwGetKey(self.ptr, key as c_int)) }
}
pub fn get_mouse_button(&self, button: MouseButton) -> Action {
unsafe { mem::transmute(ffi::glfwGetMouseButton(self.ptr, button as c_int)) }
}
pub fn get_cursor_pos(&self) -> (f64, f64) {
unsafe {
let mut xpos = 0.0;
let mut ypos = 0.0;
ffi::glfwGetCursorPos(self.ptr, &mut xpos, &mut ypos);
(xpos as f64, ypos as f64)
}
}
pub fn set_cursor_pos(&mut self, xpos: f64, ypos: f64) {
unsafe { ffi::glfwSetCursorPos(self.ptr, xpos as c_double, ypos as c_double); }
}
pub fn set_key_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetKeyCallback, key_callback);
}
pub fn set_char_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetCharCallback, char_callback);
}
pub fn set_char_mods_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetCharModsCallback, char_mods_callback);
}
pub fn set_mouse_button_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetMouseButtonCallback, mouse_button_callback);
}
pub fn set_cursor_pos_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetCursorPosCallback, cursor_pos_callback);
}
pub fn set_cursor_enter_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetCursorEnterCallback, cursor_enter_callback);
}
pub fn set_scroll_polling(&mut self, should_poll: bool) {
set_window_callback!(self, should_poll, glfwSetScrollCallback, scroll_callback);
}
pub fn set_clipboard_string(&mut self, string: &str) {
unsafe {
with_c_str(string, |string| {
ffi::glfwSetClipboardString(self.ptr, string);
});
}
}
pub fn get_clipboard_string(&self) -> Option<String> {
unsafe { string_from_nullable_c_str(ffi::glfwGetClipboardString(self.ptr)) }
}
pub fn get_opacity(&self) -> f32 {
unsafe { ffi::glfwGetWindowOpacity(self.ptr) }
}
pub fn set_opacity(&mut self, opacity: f32) {
unsafe { ffi::glfwSetWindowOpacity(self.ptr, opacity) }
}
pub fn request_attention(&mut self) {
unsafe { ffi::glfwRequestWindowAttention(self.ptr) }
}
pub fn get_content_scale(&self) -> (f32, f32) {
unsafe {
let mut xscale = 0.0_f32;
let mut yscale = 0.0_f32;
ffi::glfwGetWindowContentScale(self.ptr, &mut xscale, &mut yscale);
(xscale, yscale)
}
}
#[cfg(target_os="windows")]
pub fn get_win32_window(&self) -> *mut c_void {
unsafe { ffi::glfwGetWin32Window(self.ptr) }
}
#[cfg(target_os="windows")]
pub fn get_wgl_context(&self) -> *mut c_void {
unsafe { ffi::glfwGetWGLContext(self.ptr) }
}
#[cfg(target_os="macos")]
pub fn get_cocoa_window(&self) -> *mut c_void {
unsafe { ffi::glfwGetCocoaWindow(self.ptr) }
}
#[cfg(target_os="macos")]
pub fn get_nsgl_context(&self) -> *mut c_void {
unsafe { ffi::glfwGetNSGLContext(self.ptr) }
}
#[cfg(target_os="linux")]
pub fn get_x11_window(&self) -> *mut c_void {
unsafe { ffi::glfwGetX11Window(self.ptr) }
}
#[cfg(target_os="linux")]
pub fn get_glx_context(&self) -> *mut c_void {
unsafe { ffi::glfwGetGLXContext(self.ptr) }
}
}
impl Drop for Window {
fn drop(&mut self) {
drop(self.drop_sender.take());
if self.drop_receiver.try_recv() != Err(std::sync::mpsc::TryRecvError::Disconnected) {
debug!("Attempted to drop a Window before the `RenderContext` was dropped.");
debug!("Blocking until the `RenderContext` was dropped.");
let _ = self.drop_receiver.recv();
}
if !self.ptr.is_null() {
unsafe {
let _: Box<Sender<(f64, WindowEvent)>> = mem::transmute(ffi::glfwGetWindowUserPointer(self.ptr));
}
}
if !self.is_shared {
unsafe { ffi::glfwDestroyWindow(self.ptr); }
}
}
}
pub struct RenderContext {
ptr: *mut ffi::GLFWwindow,
#[allow(dead_code)]
drop_sender: Sender<()>,
}
unsafe impl Send for RenderContext {}
pub trait Context {
fn window_ptr(&self) -> *mut ffi::GLFWwindow;
fn window_id(&self) -> WindowId {
self.window_ptr() as WindowId
}
fn swap_buffers(&mut self) {
let ptr = self.window_ptr();
unsafe { ffi::glfwSwapBuffers(ptr); }
}
fn is_current(&self) -> bool {
self.window_ptr() == unsafe { ffi::glfwGetCurrentContext() }
}
fn make_current(&mut self) {
let ptr = self.window_ptr();
unsafe { ffi::glfwMakeContextCurrent(ptr); }
}
fn should_close(&self) -> bool {
let ptr = self.window_ptr();
unsafe { ffi::glfwWindowShouldClose(ptr) == ffi::TRUE }
}
fn set_should_close(&mut self, value: bool) {
let ptr = self.window_ptr();
unsafe { ffi::glfwSetWindowShouldClose(ptr, value as c_int); }
}
fn post_empty_event(&self) {
unsafe { ffi::glfwPostEmptyEvent() }
}
}
impl Context for Window {
fn window_ptr(&self) -> *mut ffi::GLFWwindow { self.ptr }
}
impl Context for RenderContext {
fn window_ptr(&self) -> *mut ffi::GLFWwindow { self.ptr }
}
unsafe impl HasRawWindowHandle for Window {
fn raw_window_handle(&self) -> RawWindowHandle {
raw_window_handle(self)
}
}
unsafe impl HasRawWindowHandle for RenderContext {
fn raw_window_handle(&self) -> RawWindowHandle {
raw_window_handle(self)
}
}
fn raw_window_handle<C: Context>(context: &C) -> RawWindowHandle {
#[cfg(target_family = "windows")]
{
use raw_window_handle::windows::WindowsHandle;
let hwnd = unsafe {
ffi::glfwGetWin32Window(context.window_ptr())
};
RawWindowHandle::Windows(WindowsHandle {
hwnd,
..WindowsHandle::empty()
})
}
#[cfg(any(target_os="linux", target_os="freebsd", target_os="dragonfly"))]
{
use raw_window_handle::unix::X11Handle;
let (window, display) = unsafe {
let window = ffi::glfwGetX11Window(context.window_ptr());
let display = ffi::glfwGetX11Display();
(window as std::os::raw::c_ulong, display)
};
RawWindowHandle::X11(X11Handle {
window,
display,
..X11Handle::empty()
})
}
#[cfg(target_os="macos")]
{
use raw_window_handle::macos::MacOSHandle;
let (ns_window, ns_view) = unsafe {
let ns_window: *mut objc::runtime::Object = ffi::glfwGetCocoaWindow(context.window_ptr()) as *mut _;
let ns_view: *mut objc::runtime::Object = objc::msg_send![ns_window, contentView];
assert_ne!(ns_view, std::ptr::null_mut());
(ns_window as *mut std::ffi::c_void, ns_view as *mut std::ffi::c_void)
};
RawWindowHandle::MacOS(MacOSHandle {
ns_window,
ns_view,
..MacOSHandle::empty()
})
}
}
pub fn make_context_current(context: Option<&dyn Context>) {
match context {
Some(ctx) => unsafe { ffi::glfwMakeContextCurrent(ctx.window_ptr()) },
None => unsafe { ffi::glfwMakeContextCurrent(ptr::null_mut()) },
}
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum JoystickId {
Joystick1 = ffi::JOYSTICK_1,
Joystick2 = ffi::JOYSTICK_2,
Joystick3 = ffi::JOYSTICK_3,
Joystick4 = ffi::JOYSTICK_4,
Joystick5 = ffi::JOYSTICK_5,
Joystick6 = ffi::JOYSTICK_6,
Joystick7 = ffi::JOYSTICK_7,
Joystick8 = ffi::JOYSTICK_8,
Joystick9 = ffi::JOYSTICK_9,
Joystick10 = ffi::JOYSTICK_10,
Joystick11 = ffi::JOYSTICK_11,
Joystick12 = ffi::JOYSTICK_12,
Joystick13 = ffi::JOYSTICK_13,
Joystick14 = ffi::JOYSTICK_14,
Joystick15 = ffi::JOYSTICK_15,
Joystick16 = ffi::JOYSTICK_16,
}
impl JoystickId {
pub fn from_i32(n: i32) -> Option<JoystickId> {
if n >= 0 && n <= ffi::JOYSTICK_LAST {
Some(unsafe { mem::transmute(n) })
} else {
None
}
}
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum GamepadButton {
ButtonA = ffi::GAMEPAD_BUTTON_A,
ButtonB = ffi::GAMEPAD_BUTTON_B,
ButtonX = ffi::GAMEPAD_BUTTON_X,
ButtonY = ffi::GAMEPAD_BUTTON_Y,
ButtonLeftBumper = ffi::GAMEPAD_BUTTON_LEFT_BUMPER,
ButtonRightBumper = ffi::GAMEPAD_BUTTON_RIGHT_BUMPER,
ButtonBack = ffi::GAMEPAD_BUTTON_BACK,
ButtonStart = ffi::GAMEPAD_BUTTON_START,
ButtonGuide = ffi::GAMEPAD_BUTTON_GUIDE,
ButtonLeftThumb = ffi::GAMEPAD_BUTTON_LEFT_THUMB,
ButtonRightThumb = ffi::GAMEPAD_BUTTON_RIGHT_THUMB,
ButtonDpadUp = ffi::GAMEPAD_BUTTON_DPAD_UP,
ButtonDpadRight = ffi::GAMEPAD_BUTTON_DPAD_RIGHT,
ButtonDpadDown = ffi::GAMEPAD_BUTTON_DPAD_DOWN,
ButtonDpadLeft = ffi::GAMEPAD_BUTTON_DPAD_LEFT,
}
impl GamepadButton {
pub fn from_i32(n: i32) -> Option<GamepadButton> {
if n >= 0 && n <= ffi::GAMEPAD_BUTTON_LAST {
Some(unsafe { mem::transmute(n) })
} else {
None
}
}
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum GamepadAxis {
AxisLeftX = ffi::GAMEPAD_AXIS_LEFT_X,
AxisLeftY = ffi::GAMEPAD_AXIS_LEFT_Y,
AxisRightX = ffi::GAMEPAD_AXIS_RIGHT_X,
AxisRightY = ffi::GAMEPAD_AXIS_RIGHT_Y,
AxisLeftTrigger = ffi::GAMEPAD_AXIS_LEFT_TRIGGER,
AxisRightTrigger = ffi::GAMEPAD_AXIS_RIGHT_TRIGGER,
}
impl GamepadAxis {
pub fn from_i32(n: i32) -> Option<GamepadAxis> {
if n >= 0 && n <= ffi::GAMEPAD_AXIS_LAST {
Some(unsafe { mem::transmute(n) })
} else {
None
}
}
}
bitflags! {
#[doc = "Joystick hats."]
pub struct JoystickHats: ::libc::c_int {
const Centered = ::ffi::HAT_CENTERED;
const Up = ::ffi::HAT_UP;
const Right = ::ffi::HAT_RIGHT;
const Down = ::ffi::HAT_DOWN;
const Left = ::ffi::HAT_LEFT;
}
}
#[derive(Clone)]
pub struct Joystick {
pub id: JoystickId,
pub glfw: Glfw,
}
pub struct GamepadState {
buttons: [Action; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize],
axes: [f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize],
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum JoystickEvent {
Connected = ffi::CONNECTED,
Disconnected = ffi::DISCONNECTED,
}
pub type JoystickCallback<UserData> = Callback<fn(JoystickId, JoystickEvent, &UserData), UserData>;
impl Joystick {
pub fn is_present(&self) -> bool {
unsafe { ffi::glfwJoystickPresent(self.id as c_int) == ffi::TRUE }
}
pub fn get_axes(&self) -> Vec<f32> {
unsafe {
let mut count = 0;
let ptr = ffi::glfwGetJoystickAxes(self.id as c_int, &mut count);
slice::from_raw_parts(ptr, count as usize).iter().map(|&a| a as f32).collect()
}
}
pub fn get_buttons(&self) -> Vec<c_int> {
unsafe {
let mut count = 0;
let ptr = ffi::glfwGetJoystickButtons(self.id as c_int, &mut count);
slice::from_raw_parts(ptr, count as usize).iter().map(|&b| b as c_int).collect()
}
}
pub fn get_hats(&self) -> Vec<JoystickHats> {
unsafe {
let mut count = 0;
let ptr = ffi::glfwGetJoystickHats(self.id as c_int, &mut count);
slice::from_raw_parts(ptr, count as usize).iter().map(|&b| mem::transmute(b as c_int)).collect()
}
}
pub fn get_name(&self) -> Option<String> {
unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickName(self.id as c_int)) }
}
pub fn get_guid(&self) -> Option<String> {
unsafe { string_from_nullable_c_str(ffi::glfwGetJoystickGUID(self.id as c_int)) }
}
pub fn is_gamepad(&self) -> bool {
unsafe { ffi::glfwJoystickIsGamepad(self.id as c_int) == ffi::TRUE }
}
pub fn get_gamepad_name(&self) -> Option<String> {
unsafe { string_from_nullable_c_str(ffi::glfwGetGamepadName(self.id as c_int)) }
}
pub fn get_gamepad_state(&self) -> Option<GamepadState> {
unsafe {
let mut state = ffi::GLFWgamepadstate {
buttons: [0; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize],
axes: [0_f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize],
};
if ffi::glfwGetGamepadState(self.id as c_int, &mut state) == ffi::TRUE {
Some(state.into())
} else {
None
}
}
}
}
impl From<ffi::GLFWgamepadstate> for GamepadState {
fn from(state: ffi::GLFWgamepadstate) -> Self {
let mut buttons = [Action::Release; (ffi::GAMEPAD_BUTTON_LAST + 1) as usize];
let mut axes = [0_f32; (ffi::GAMEPAD_AXIS_LAST + 1) as usize];
unsafe {
state.buttons.iter().map(|&b| mem::transmute(b as c_int))
.zip(buttons.iter_mut()).for_each(|(a, b)| *b = a);
}
state.axes.iter().map(|&f| f as f32)
.zip(axes.iter_mut()).for_each(|(a, b)| *b = a);
Self {
buttons,
axes,
}
}
}
impl GamepadState {
pub fn get_button_state(&self, button: GamepadButton) -> Action {
self.buttons[button as usize]
}
pub fn get_axis(&self, axis: GamepadAxis) -> f32 {
self.axes[axis as usize]
}
}