glutin/
lib.rs

1//! The purpose of this library is to provide an OpenGL context on as many
2//!  platforms as possible.
3//!
4//! # Building a window
5//!
6//! There are two ways to create a window:
7//!
8//!  - Calling `Window::new()`.
9//!  - Calling `let builder = WindowBuilder::new()` then `builder.build()`.
10//!
11//! The first way is the simpliest way and will give you default values.
12//!
13//! The second way allows you to customize the way your window and GL context
14//!  will look and behave.
15//!
16//! # Features
17//!
18//! This crate has two Cargo features: `window` and `headless`.
19//!
20//!  - `window` allows you to create regular windows and enables the `WindowBuilder` object.
21//!  - `headless` allows you to do headless rendering, and enables
22//!     the `HeadlessRendererBuilder` object.
23//!
24//! By default only `window` is enabled.
25
26#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "windows"))]
27#[macro_use]
28extern crate lazy_static;
29
30#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
31#[macro_use]
32extern crate shared_library;
33
34extern crate libc;
35
36#[cfg(target_os = "windows")]
37extern crate winapi;
38#[cfg(target_os = "windows")]
39extern crate kernel32;
40#[cfg(target_os = "windows")]
41extern crate shell32;
42#[cfg(target_os = "windows")]
43extern crate gdi32;
44#[cfg(target_os = "windows")]
45extern crate user32;
46#[cfg(target_os = "windows")]
47extern crate dwmapi;
48#[cfg(any(target_os = "macos", target_os = "ios"))]
49#[macro_use]
50extern crate objc;
51#[cfg(target_os = "macos")]
52extern crate cgl;
53#[cfg(target_os = "macos")]
54extern crate cocoa;
55#[cfg(target_os = "macos")]
56extern crate core_foundation;
57#[cfg(target_os = "macos")]
58extern crate core_graphics;
59#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
60extern crate x11_dl;
61#[cfg(all(feature = "image",
62          any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd")))]
63extern crate image;
64
65pub use events::*;
66pub use headless::{HeadlessRendererBuilder, HeadlessContext};
67pub use window::{WindowProxy, PollEventsIterator, WaitEventsIterator};
68pub use window::{AvailableMonitorsIter, MonitorId, get_available_monitors, get_primary_monitor};
69pub use native_monitor::NativeMonitorId;
70
71use std::io;
72#[cfg(all(not(target_os = "macos"),not(target_os = "ios")))]
73use std::cmp::Ordering;
74use std::path::PathBuf;
75
76mod api;
77mod platform;
78mod events;
79mod headless;
80mod window;
81
82pub mod os;
83
84/// Represents an OpenGL context and the Window or environment around it.
85///
86/// # Example
87///
88/// ```ignore
89/// let window = Window::new().unwrap();
90///
91/// unsafe { window.make_current() };
92///
93/// loop {
94///     for event in window.poll_events() {
95///         match(event) {
96///             // process events here
97///             _ => ()
98///         }
99///     }
100///
101///     // draw everything here
102///
103///     window.swap_buffers();
104///     std::old_io::timer::sleep(17);
105/// }
106/// ```
107pub struct Window {
108    window: platform::Window,
109}
110
111/// Object that allows you to build windows.
112#[derive(Clone)]
113pub struct WindowBuilder<'a> {
114    /// The attributes to use to create the window.
115    pub window: WindowAttributes,
116
117    /// The attributes to use to create the context.
118    pub opengl: GlAttributes<&'a platform::Window>,
119
120    // Should be made public once it's stabilized.
121    pf_reqs: PixelFormatRequirements,
122
123    /// Platform-specific configuration.
124    platform_specific: platform::PlatformSpecificWindowBuilderAttributes,
125}
126
127/// Trait that describes objects that have access to an OpenGL context.
128pub trait GlContext {
129    /// Sets the context as the current context.
130    unsafe fn make_current(&self) -> Result<(), ContextError>;
131
132    /// Returns true if this context is the current one in this thread.
133    fn is_current(&self) -> bool;
134
135    /// Returns the address of an OpenGL function.
136    fn get_proc_address(&self, addr: &str) -> *const ();
137
138    /// Swaps the buffers in case of double or triple buffering.
139    ///
140    /// You should call this function every time you have finished rendering, or the image
141    /// may not be displayed on the screen.
142    ///
143    /// **Warning**: if you enabled vsync, this function will block until the next time the screen
144    /// is refreshed. However drivers can choose to override your vsync settings, which means that
145    /// you can't know in advance whether `swap_buffers` will block or not.
146    fn swap_buffers(&self) -> Result<(), ContextError>;
147
148    /// Returns the OpenGL API being used.
149    fn get_api(&self) -> Api;
150
151    /// Returns the pixel format of the main framebuffer of the context.
152    fn get_pixel_format(&self) -> PixelFormat;
153}
154
155/// Error that can happen while creating a window or a headless renderer.
156#[derive(Debug)]
157pub enum CreationError {
158    OsError(String),
159    /// TODO: remove this error
160    NotSupported,
161    NoBackendAvailable(Box<std::error::Error + Send>),
162    RobustnessNotSupported,
163    OpenGlVersionNotSupported,
164    NoAvailablePixelFormat,
165}
166
167impl CreationError {
168    fn to_string(&self) -> &str {
169        match *self {
170            CreationError::OsError(ref text) => &text,
171            CreationError::NotSupported => "Some of the requested attributes are not supported",
172            CreationError::NoBackendAvailable(_) => "No backend is available",
173            CreationError::RobustnessNotSupported => "You requested robustness, but it is \
174                                                      not supported.",
175            CreationError::OpenGlVersionNotSupported => "The requested OpenGL version is not \
176                                                         supported.",
177            CreationError::NoAvailablePixelFormat => "Couldn't find any pixel format that matches \
178                                                      the criterias.",
179        }
180    }
181}
182
183impl std::fmt::Display for CreationError {
184    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
185        formatter.write_str(self.to_string())
186    }
187}
188
189impl std::error::Error for CreationError {
190    fn description(&self) -> &str {
191        self.to_string()
192    }
193
194    fn cause(&self) -> Option<&std::error::Error> {
195        match *self {
196            CreationError::NoBackendAvailable(ref err) => Some(&**err),
197            _ => None
198        }
199    }
200}
201
202/// Error that can happen when manipulating an OpenGL context.
203#[derive(Debug)]
204pub enum ContextError {
205    IoError(io::Error),
206    ContextLost,
207}
208
209impl ContextError {
210    fn to_string(&self) -> &str {
211        use std::error::Error;
212        match *self {
213            ContextError::IoError(ref err) => err.description(),
214            ContextError::ContextLost => "Context lost"
215        }
216    }
217}
218
219impl std::fmt::Display for ContextError {
220    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
221        formatter.write_str(self.to_string())
222    }
223}
224
225impl std::error::Error for ContextError {
226    fn description(&self) -> &str {
227        self.to_string()
228    }
229}
230
231/// All APIs related to OpenGL that you can possibly get while using glutin.
232#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233pub enum Api {
234    /// The classical OpenGL. Available on Windows, Linux, OS/X.
235    OpenGl,
236    /// OpenGL embedded system. Available on Linux, Android.
237    OpenGlEs,
238    /// OpenGL for the web. Very similar to OpenGL ES.
239    WebGl,
240}
241
242/// Describes the requested OpenGL context profiles.
243#[derive(Debug, Clone, Copy, PartialEq, Eq)]
244pub enum GlProfile {
245    /// Include all the immediate more functions and definitions.
246    Compatibility,
247    /// Include all the future-compatible functions and definitions.
248    Core,
249}
250
251/// Describes the OpenGL API and version that are being requested when a context is created.
252#[derive(Debug, Copy, Clone)]
253pub enum GlRequest {
254    /// Request the latest version of the "best" API of this platform.
255    ///
256    /// On desktop, will try OpenGL.
257    Latest,
258
259    /// Request a specific version of a specific API.
260    ///
261    /// Example: `GlRequest::Specific(Api::OpenGl, (3, 3))`.
262    Specific(Api, (u8, u8)),
263
264    /// If OpenGL is available, create an OpenGL context with the specified `opengl_version`.
265    /// Else if OpenGL ES or WebGL is available, create a context with the
266    /// specified `opengles_version`.
267    GlThenGles {
268        /// The version to use for OpenGL.
269        opengl_version: (u8, u8),
270        /// The version to use for OpenGL ES.
271        opengles_version: (u8, u8),
272    },
273}
274
275impl GlRequest {
276    /// Extract the desktop GL version, if any.
277    pub fn to_gl_version(&self) -> Option<(u8, u8)> {
278        match self {
279            &GlRequest::Specific(Api::OpenGl, version) => Some(version),
280            &GlRequest::GlThenGles { opengl_version: version, .. } => Some(version),
281            _ => None,
282        }
283    }
284}
285
286/// The minimum core profile GL context. Useful for getting the minimum
287/// required GL version while still running on OSX, which often forbids
288/// the compatibility profile features.
289pub static GL_CORE: GlRequest = GlRequest::Specific(Api::OpenGl, (3, 2));
290
291/// Specifies the tolerance of the OpenGL context to faults. If you accept raw OpenGL commands
292/// and/or raw shader code from an untrusted source, you should definitely care about this.
293#[derive(Debug, Copy, Clone, PartialEq, Eq)]
294pub enum Robustness {
295    /// Not everything is checked. Your application can crash if you do something wrong with your
296    /// shaders.
297    NotRobust,
298
299    /// The driver doesn't check anything. This option is very dangerous. Please know what you're
300    /// doing before using it. See the `GL_KHR_no_error` extension.
301    ///
302    /// Since this option is purely an optimisation, no error will be returned if the backend
303    /// doesn't support it. Instead it will automatically fall back to `NotRobust`.
304    NoError,
305
306    /// Everything is checked to avoid any crash. The driver will attempt to avoid any problem,
307    /// but if a problem occurs the behavior is implementation-defined. You are just guaranteed not
308    /// to get a crash.
309    RobustNoResetNotification,
310
311    /// Same as `RobustNoResetNotification` but the context creation doesn't fail if it's not
312    /// supported.
313    TryRobustNoResetNotification,
314
315    /// Everything is checked to avoid any crash. If a problem occurs, the context will enter a
316    /// "context lost" state. It must then be recreated. For the moment, glutin doesn't provide a
317    /// way to recreate a context with the same window :-/
318    RobustLoseContextOnReset,
319
320    /// Same as `RobustLoseContextOnReset` but the context creation doesn't fail if it's not
321    /// supported.
322    TryRobustLoseContextOnReset,
323}
324
325/// The behavior of the driver when you change the current context.
326#[derive(Debug, Copy, Clone, PartialEq, Eq)]
327pub enum ReleaseBehavior {
328    /// Doesn't do anything. Most notably doesn't flush.
329    None,
330
331    /// Flushes the context that was previously current as if `glFlush` was called.
332    Flush,
333}
334
335#[derive(Debug, Copy, Clone, PartialEq)]
336pub enum MouseCursor {
337    /// The platform-dependent default cursor.
338    Default,
339    /// A simple crosshair.
340    Crosshair,
341    /// A hand (often used to indicate links in web browsers).
342    Hand,
343    /// Self explanatory.
344    Arrow,
345    /// Indicates something is to be moved.
346    Move,
347    /// Indicates text that may be selected or edited.
348    Text,
349    /// Program busy indicator.
350    Wait,
351    /// Help indicator (often rendered as a "?")
352    Help,
353    /// Progress indicator. Shows that processing is being done. But in contrast
354    /// with "Wait" the user may still interact with the program. Often rendered
355    /// as a spinning beach ball, or an arrow with a watch or hourglass.
356    Progress,
357
358    /// Cursor showing that something cannot be done.
359    NotAllowed,
360    ContextMenu,
361    NoneCursor,
362    Cell,
363    VerticalText,
364    Alias,
365    Copy,
366    NoDrop,
367    Grab,
368    Grabbing,
369    AllScroll,
370    ZoomIn,
371    ZoomOut,
372
373    /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor
374    /// is used when the movement starts from the south-east corner of the box.
375    EResize,
376    NResize,
377    NeResize,
378    NwResize,
379    SResize,
380    SeResize,
381    SwResize,
382    WResize,
383    EwResize,
384    NsResize,
385    NeswResize,
386    NwseResize,
387    ColResize,
388    RowResize,
389}
390
391/// Describes how glutin handles the cursor.
392#[derive(Debug, Copy, Clone, PartialEq)]
393pub enum CursorState {
394    /// Normal cursor behavior.
395    Normal,
396
397    /// The cursor will be invisible when over the window.
398    Hide,
399
400    /// Grabs the mouse cursor. The cursor's motion will be confined to this
401    /// window and the window has exclusive access to further events regarding
402    /// the cursor.
403    ///
404    /// This is useful for first-person cameras for example.
405    Grab,
406}
407
408/// Describes a possible format. Unused.
409#[allow(missing_docs)]
410#[derive(Debug, Clone)]
411pub struct PixelFormat {
412    pub hardware_accelerated: bool,
413    pub color_bits: u8,
414    pub alpha_bits: u8,
415    pub depth_bits: u8,
416    pub stencil_bits: u8,
417    pub stereoscopy: bool,
418    pub double_buffer: bool,
419    pub multisampling: Option<u16>,
420    pub srgb: bool,
421}
422
423/// Describes how the backend should choose a pixel format.
424// TODO: swap method? (swap, copy)
425#[derive(Clone, Debug)]
426pub struct PixelFormatRequirements {
427    /// If true, only hardware-accelerated formats will be conisdered. If false, only software
428    /// renderers. `None` means "don't care". Default is `Some(true)`.
429    pub hardware_accelerated: Option<bool>,
430
431    /// Minimum number of bits for the color buffer, excluding alpha. `None` means "don't care".
432    /// The default is `Some(24)`.
433    pub color_bits: Option<u8>,
434
435    /// If true, the color buffer must be in a floating point format. Default is `false`.
436    ///
437    /// Using floating points allows you to write values outside of the `[0.0, 1.0]` range.
438    pub float_color_buffer: bool,
439
440    /// Minimum number of bits for the alpha in the color buffer. `None` means "don't care".
441    /// The default is `Some(8)`.
442    pub alpha_bits: Option<u8>,
443
444    /// Minimum number of bits for the depth buffer. `None` means "don't care".
445    /// The default value is `Some(24)`.
446    pub depth_bits: Option<u8>,
447
448    /// Minimum number of bits for the depth buffer. `None` means "don't care".
449    /// The default value is `Some(8)`.
450    pub stencil_bits: Option<u8>,
451
452    /// If true, only double-buffered formats will be considered. If false, only single-buffer
453    /// formats. `None` means "don't care". The default is `Some(true)`.
454    pub double_buffer: Option<bool>,
455
456    /// Contains the minimum number of samples per pixel in the color, depth and stencil buffers.
457    /// `None` means "don't care". Default is `None`.
458    /// A value of `Some(0)` indicates that multisampling must not be enabled.
459    pub multisampling: Option<u16>,
460
461    /// If true, only stereoscopic formats will be considered. If false, only non-stereoscopic
462    /// formats. The default is `false`.
463    pub stereoscopy: bool,
464
465    /// If true, only sRGB-capable formats will be considered. If false, don't care.
466    /// The default is `false`.
467    pub srgb: bool,
468
469    /// The behavior when changing the current context. Default is `Flush`.
470    pub release_behavior: ReleaseBehavior,
471}
472
473impl Default for PixelFormatRequirements {
474    #[inline]
475    fn default() -> PixelFormatRequirements {
476        PixelFormatRequirements {
477            hardware_accelerated: Some(true),
478            color_bits: Some(24),
479            float_color_buffer: false,
480            alpha_bits: Some(8),
481            depth_bits: Some(24),
482            stencil_bits: Some(8),
483            double_buffer: None,
484            multisampling: None,
485            stereoscopy: false,
486            srgb: false,
487            release_behavior: ReleaseBehavior::Flush,
488        }
489    }
490}
491
492/// A wrapper for a native window pointer.
493#[derive(Debug, Clone)]
494pub struct WindowID {
495    pub window: *mut libc::c_void,
496}
497
498impl WindowID {
499    pub fn new(window: *mut libc::c_void) -> WindowID {
500        WindowID {
501            window: window
502        }
503    }
504}
505
506unsafe impl Send for WindowID {}
507unsafe impl Sync for WindowID {}
508
509/// Attributes to use when creating a window.
510#[derive(Clone)]
511pub struct WindowAttributes {
512    /// The dimensions of the window. If this is `None`, some platform-specific dimensions will be
513    /// used.
514    ///
515    /// The default is `None`.
516    pub dimensions: Option<(u32, u32)>,
517
518    /// The minimum dimensions a window can be, If this is `None`, the window will have no minimum dimensions (aside from reserved).
519    ///
520    /// The default is `None`.
521    pub min_dimensions: Option<(u32, u32)>,
522
523    /// The maximum dimensions a window can be, If this is `None`, the maximum will have no maximum or will be set to the primary monitor's dimensions by the platform.
524    ///
525    /// The default is `None`.
526    pub max_dimensions: Option<(u32, u32)>,
527
528    /// If `Some`, the window will be in fullscreen mode with the given monitor.
529    ///
530    /// The default is `None`.
531    pub monitor: Option<platform::MonitorId>,
532
533    /// The title of the window in the title bar.
534    ///
535    /// The default is `"glutin window"`.
536    pub title: String,
537
538    /// Whether the window should be immediately visible upon creation.
539    ///
540    /// The default is `true`.
541    pub visible: bool,
542
543    /// Whether the the window should be transparent. If this is true, writing colors
544    /// with alpha values different than `1.0` will produce a transparent window.
545    ///
546    /// The default is `false`.
547    pub transparent: bool,
548
549    /// Whether the window should have borders and bars.
550    ///
551    /// The default is `true`.
552    pub decorations: bool,
553
554    /// [iOS only] Enable multitouch, see [UIView#multipleTouchEnabled]
555    /// (https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/multipleTouchEnabled)
556    pub multitouch: bool,
557
558    /// A path to an icon for the window. This may not be supported on every windowing system.
559    /// If present, this path must reference a PNG file.
560    ///
561    /// The default is `None`.
562    pub icon: Option<PathBuf>,
563
564    /// Parent Window.
565    ///
566    /// The default is `None`.
567    pub parent: Option<WindowID>,
568}
569
570impl Default for WindowAttributes {
571    #[inline]
572    fn default() -> WindowAttributes {
573        WindowAttributes {
574            dimensions: None,
575            min_dimensions: None,
576            max_dimensions: None,
577            monitor: None,
578            title: "glutin window".to_owned(),
579            visible: true,
580            transparent: false,
581            decorations: true,
582            multitouch: false,
583            icon: None,
584            parent: None,
585        }
586    }
587}
588
589/// Attributes to use when creating an OpenGL context.
590#[derive(Clone)]
591pub struct GlAttributes<S> {
592    /// An existing context to share the new the context with.
593    ///
594    /// The default is `None`.
595    pub sharing: Option<S>,
596
597    /// Version to try create. See `GlRequest` for more infos.
598    ///
599    /// The default is `Latest`.
600    pub version: GlRequest,
601
602    /// OpenGL profile to use.
603    ///
604    /// The default is `None`.
605    pub profile: Option<GlProfile>,
606
607    /// Whether to enable the `debug` flag of the context.
608    ///
609    /// Debug contexts are usually slower but give better error reporting.
610    ///
611    /// The default is `true` in debug mode and `false` in release mode.
612    pub debug: bool,
613
614    /// How the OpenGL context should detect errors.
615    ///
616    /// The default is `NotRobust` because this is what is typically expected when you create an
617    /// OpenGL context. However for safety you should consider `TryRobustLoseContextOnReset`.
618    pub robustness: Robustness,
619
620    /// Whether to use vsync. If vsync is enabled, calling `swap_buffers` will block until the
621    /// screen refreshes. This is typically used to prevent screen tearing.
622    ///
623    /// The default is `false`.
624    pub vsync: bool,
625}
626
627impl<S> GlAttributes<S> {
628    /// Turns the `sharing` parameter into another type by calling a closure.
629    #[inline]
630    pub fn map_sharing<F, T>(self, f: F) -> GlAttributes<T> where F: FnOnce(S) -> T {
631        GlAttributes {
632            sharing: self.sharing.map(f),
633            version: self.version,
634            profile: self.profile,
635            debug: self.debug,
636            robustness: self.robustness,
637            vsync: self.vsync,
638        }
639    }
640}
641
642impl<S> Default for GlAttributes<S> {
643    #[inline]
644    fn default() -> GlAttributes<S> {
645        GlAttributes {
646            sharing: None,
647            version: GlRequest::Latest,
648            profile: None,
649            debug: cfg!(debug_assertions),
650            robustness: Robustness::NotRobust,
651            vsync: false,
652        }
653    }
654}
655
656mod native_monitor {
657    /// Native platform identifier for a monitor. Different platforms use fundamentally different types
658    /// to represent a monitor ID.
659    #[derive(Clone, PartialEq, Eq)]
660    pub enum NativeMonitorId {
661        /// Cocoa and X11 use a numeric identifier to represent a monitor.
662        Numeric(u32),
663
664        /// Win32 uses a Unicode string to represent a monitor.
665        Name(String),
666
667        /// Other platforms (Android) don't support monitor identification.
668        Unavailable
669    }
670}